Download the PHP package lechimp-p/php-formlets without Composer
On this page you can find all versions of the php package lechimp-p/php-formlets. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.
Download lechimp-p/php-formlets
More information about lechimp-p/php-formlets
Files in lechimp-p/php-formlets
Package php-formlets
Short Description Composable forms(let)s, "The Essence of Form Abstraction" in PHP
License MIT
Homepage https://github.com/lechimp-p/php-formlets
Informations about the package php-formlets
php-formlets
Create highly composable forms in PHP. Implementation of ideas from "The Essence of Form Abstraction" from Cooper, Lindley, Wadler and Yallop.
Writing up formulars is a big part in the every days business of PHP-developers. To ease this work, one would like to abstract the formulars in a way that makes them composable. This is the implementation of an attempt to this problem grown from functional programming and elaborated scientifically.
It could be usefull for educational purpose, since it implements some interesting concepts. I'm also interested in real world applications of the code, but i'm not quite sure, weather the code is really ready for that atm. The concepts used in the implementation might feel somehow strange to PHPers anyway (and others as well), so i will start with some explanation of the concepts and how one could use them for a framework to create forms. Hf.
This README.md is also a literate PHP-file.
This code is released under the MIT License
Functions as Values, Currying
To understand the first important ingredient of the formlet abstraction, we need to look at functions in a different way then we are used to from PHP.
The functions we need for this abstraction could be used as ordinary values, that is they can be stored in a variable, being passed around or used as an argument to another function. Functions in PHP in opposite are not that volatile, mostly you call them by their name. You could off course use some PHP magic like $function_name() to come a bit closer to the afformentioned property of functions and PHPs callable aims at this direction.
The functions in our abstraction also all need to have an arity (that is amount of arguments) of one. How to do something like explode(" ", $foo) then, you might wonder. Easy. Since functions are ordinary values in our abstraction, you just create a function that takes the delimiter and returns a function that splits a string at the delimiter. That also means you could call a function partially. PHP functions are rather different. You always call them at once.
The function evaluation works lazy, that is it only calculates the value when
it is really needed the first time. In our case that is the moment we call
$res->get()
. You will be safe in terms of the result of function applications
if you only use functions without sideeffects like writing or reading global
stuff. When using functions with sideeffects, the result might be suprising.
For the later use with the formlets, values can be erroneous to catch an
exception from the underlying PHP function and turn it into an error value,
one can use catchAndReify
to create a new function value.
The whole machinery should be working in an immutable style (except for HTML representation), that is creating new values instead of modifying old. The same goes for the rest of the stuff. The related classes and functions could be found at the section starting with the class Value in formlets.php.
Form(let)s as Applicative Functors
The building blog of our forms are called formlets, and they behave according to an abstraction called applicative functor. We'll try to understand both alongside, there's enough stuff about the abstract concept on the net.
A formlet is a thing that encapsulates two things, a renderer and a collector, in a highly composable way. The renderer is the entity that creates HTML output, while the collector is responsible for collecting values from the user input. The most simple formlet thus is a formlet that renders to nothing and 'collects' a constant value, regardless of the user input.
After creating some reusable formlets, we can turn a formlet into an actual form that could be rendered, is able to yield a result and abstracts away some plumbing.
A formlet is a functor, since in some sense every formlet contains a value. And we can map over that value, that is apply a function to that value inside the formlet, yielding a new formlet containing the result of the function call.
A formlet is applicative, since it provides an interesting way of combining two formlets into a new one. If you have two formlets, one collecting a function and rendering some output, and the other collecting a value and rendering some other output, you can combine them to a new formlet, 'collecting' the function applied to the value and rendering the concatenated outputs of the other formlets.
To do checks on inputs, one can use the satisfies
method, to attach a predicate
to a formlet. As the other operations, this creates a new formlet, so the old
one could be reused. When the value in the formlet fails the predicate, there is
an error in the form.
Primitives and Application
Now you need to see, how this stuff works out. I'll show you an example how one create a form using some of the primitives that are provided in the consumer interface to the library.
First we'll write our own (and very dump) date class. We won't be doing this in The Real World, i guess, but here we'll do it to see how it works more easily. We'll also need some boilerplate to make everything work out nicely. If this stuff would ever be used, i would expect a lot of this be going into a the library for reuse.
After the boilerplate, we start with the interesting stuff, that is actually
constructing a form from the two primitives. We start by creating some basic
input elements we'll need from the only input element i provide atm, the
text_input
.
Next we'll be combining these basic inputs to a more complex input that could
be used to define a date. We also use the other primitive i have implemented
atm, that is text
, which renders a static string and collects nothing. To
compose the formlets to our date formlet, we use the cmb
(for combine) method,
shown above, through the convenience function formlet
. We plumb the stuff with
$mkDate to get a formlet that creates us a date object.
That's it. Since we never modify existing objects, the stuff above could be completely reused and combined to even more complex formlets. E.g. one could use the date formlet twice to create a period formlet. Now lets try it out: