PHP code example of lechimp-p / php-formlets

1. Go to this page and download the library: Download lechimp-p/php-formlets library. Choose the download type require.

2. Extract the ZIP file and open the index.php.

3. Add this code to the index.php.
    
        
<?php
require_once('vendor/autoload.php');

/* Start to develop here. Best regards https://php-download.com/ */

    

lechimp-p / php-formlets example snippets




// We propably use a better autoloader in a real setting.
t from an ordinary PHP function. Since explode takes
// two mandatory and one optional parameter, we have to explicitly tell how many
// optional parameters we want to have. 
$explode = F::fun("explode", 2);

// For the lib to work, we need to treat functions and values the same,
// so we need to lift ordinary values to our abstraction.
$delim = F::val(" ");
$string = F::val("foo bar");

// We could apply the function once to the delim, creating a new function.
$explodeBySpace = $explode->apply($delim);

// We could apply the function to the string to create the final result:
$res = $explodeBySpace->apply($string);

// Since the value is still wrapped, we need to unwrap it.
$unwrapped = $res->get();

echo "Array containing \"foo\" and \"bar\":\n";
print_r($unwrapped);



$throws = F::fun(function ($foo) {
    throw new Exception("I knew this would happen.");
    return $foo;
});

$throwsAndCatches = $throws->catchAndReify("Exception");

$res = $throwsAndCatches->apply(F::val("But it won't..."));
echo "This will state my hindsight:\n";
echo ($res->isError()?$res->error():$res->get())."\n";


// Really not too interesting, but we need to use our value abstraction.
$boringFormlet = F::inject(F::val("Hello World!"));

// Since functions are values as well, we could construct a formlet containing 
// a function.
$functionFormlet = F::inject($explodeBySpace);



// We need to specify an id for the form and an action target.
$form = F::form("boring", "www.example.com", $boringFormlet); 

// We initialize the form with an empty input array. One could
// use init without args to use $_POST as input.
$form->init(array());

// Renderer does nothing
echo "This will show \"No content\":\n";
echo ("<form method=\"post\" action=\"www.example.com\"></form>" == $form->html() 
     ? "No content\n"
     : "Oh, that's not pure...\n"
     );

// The form has a constant result as expected.
echo "This will show \"Hello World!\":\n";
echo $form->result()."\n";



// The function to map over the formlet is called mapCollector, since it leaves
// the builder untouched. Maybe at some point a mapRenderer might come in handy
// too...
$containsArrayFormlet = $boringFormlet->map($explodeBySpace);

$form = F::form("contains_array", "www.example.com", $containsArrayFormlet); 
$form->init(array());

echo "Array containing \"Hello\" and \"World!\":\n";
print_r($form->result());


// Will be a lot more interesting when you see formlets that actually take some 
// input.
$exploded = F::inject($explode)
                ->cmb(F::inject($delim))
                ->cmb(F::inject($string))
                ;

$form = F::form("explode", "www.example.com", $exploded);
$form->init(array());

echo "Array containing \"foo\" and \"bar\":\n";
print_r($form->result());



// fun also supports defining some fixed arguments.
$containsHello = F::fun("preg_match", 2, array("/.*hello.*/i"));

// Append the predicate to a formlet. If its not truthy for the value in the 
// formlet, an error value with the given message will be collected.
$withPred = F::inject(F::val("Hi there."))
                ->satisfies($containsHello, "You should say hello.");

$form = F::form("with_pred", "www.example.com", $withPred);
$form->init(array());

echo "This will be stating, what you should say:\n";
echo ($form->wasSuccessfull() ? $form->result() : $form->error())."\n";




// Maybe next time we'll use a Wheel as example.
class _Date {
    public function __construct($y, $m, $d) {
        if (!is_int($y) || !is_int($m) || !is_int($d)) {
            throw new Exception("Expected int's as input.");
        }

        if ($m < 1 || $m > 12) {
            throw new Exception("Invalid month: '%m'.");
        }

        if ($d > 31) {
            throw new Exception("Invalid day: '%d'.");
        }

        if ($m === 2 && $d > 29) {
            throw new Exception("Month is 2 but day is $d.");
        }
        if (in_array($m, array(4,6,9,11)) && $d > 30) {
            throw new Exception("Month is $m but day is $d.");
        }

        $this->y = $y;
        $this->m = $m;
        $this->d = $d;
    }

    public function toISO() {
        return $this->y."-".$this->m."-".$this->d;
    }
}

// Our constructor function. We want to catch Exceptions since the constructor
// of the class could throw. In the real world we would be more specific
// on the type of exception we want to catch.
$mkDate = F::fun(function ($y, $m, $d) {
        return new _Date($y, $m, $d);
})
->catchAndReify("Exception")
;

function inRange($l, $r) {
    return F::fun(function($value) use ($l, $r) {
        return $value >= $l && $value <= $r;
    });
}



// First we create an integer input from a text input by map intval over the
// string input after checking it is indeed an integer. We also want to
// display the errors.
$int_formlet = F::with_errors(F::text_input())
                ->satisfies(F::fun("is_numeric"), "No integer.")
                ->map(F::fun("intval", 1))
                ;

// From the integer input we'll create a month and day input by doing further
// checks on the input. Make sure you understand, that none of these touches
// the int_formlet, but rather creates new objects.
$month_formlet = $int_formlet
    ->satisfies(inRange(1,12), "Month must have value between 1 and 12.")
    ;
$day_formlet = $int_formlet
    ->satisfies(inRange(1,31), "Day must have value between 1 and 31.")
    ;


// We use a convenience function here to not have cmb that often.
$date_formlet = F::formlet(
                    F::inject($mkDate),
                        F::text("\n\t"), // for readability on cli only
                    F::with_label("Year: ", $int_formlet),
                        F::text("\n\t"), // for readability on cli only
                    F::with_label("Month: ", $month_formlet),
                        F::text("\n\t"), // for readability on cli only
                    F::with_label("Day: ", $day_formlet),
                        F::text("\n") // for readability on cli only
                );


// You got that step, right?
$form = F::form("date", "www.example.com", $date_formlet);
$form->init(array());

// First look at the rendering:
echo "This will show some date input in HTML representation:\n";
echo $form->html()."\n\n";

// Then lets look at the collected values. Since we don't actually POST the 
// form, we need to mock up some input. 
$mock_post1 = array( "date_input_0" => "2014"
                   , "date_input_1" => "12"
                   , "date_input_2" => "24"
                   );

// We could use init without parameters if we wanted to use $_POST as input.
$form->init($mock_post1);

echo "This will show a date of christmas eve:\n";
echo $form->result()->toISO()."\n\n";


// To see how errors will show up in the formlets, lets try the same with faulty
// input:
$mock_post2 = array( "date_input_0" => "2014"
                   , "date_input_1" => "12"
                   , "date_input_2" => "32" // that would make a long month
                   );

$form->init($mock_post2);

echo "This will tell why creation of date object did not work:\n";
echo ($form->wasSuccessfull() ? $form->result()->toISO() : $form->error())."\n\n";

// So there's something wrong, and we most likely want to reprompt the user with 
// the form, stating the problem.
echo "This will show some HTML of the formlet with error messages:\n";
echo $form->html();