I know this sounds very much like "Is there a PHP framework that does my entire job for me?" But bear with me.
Say I want to create a signup form for a camp, and I have a simple data structure in mind --
Person
Address
etc
Things I have seen that do part but not all of what I want:
PHP form libraries like jFormer and ValidForm (not to mention all the big frameworks): these things let you define the form you want to make using a little bit of PHP -- so you'd say "add text field, add textarea", etc -- but they don't let the user edit the form data structure, nor do they automatically save into a data structure. They're more useful for developers.
Front-end form creators like foxyform, jotform: they let the user edit the form but the backend needs to be done in some other way, and it's not linked up.
Then there's Wordpress Pods CMS, which is almost exactly what I want -- but without the wordpress part.
Ideally, I would like one of two things:
1) A microframework where you define your data schema in some reasonably simple way, like say Json or Yaml -- your basic
Person
First name: Text
Last name: Text
Address: has_one Address
Address
... and so on
And it would take that and create the form you needed and maybe even create the database schema and so forth. You could then get hold of the data objects to iterate over in your code elsewhere (I'm not crazy enough to try and automate that as well... Or maybe I am, but certainly it feels outside the scope of this particular encapsulation).
OR
2) The above, plus a little editor for editing the data schema.
Create data type:
Name: [Person]
Fields:
First name: [Text field]
[+ Add field]
I have had a good look around and haven't found anything that's small and standalone and does just this. Pods CMS is almost exactly what I want, but smaller and cleaner and not tied to Wordpress.
Does such a thing exist? If not -- and I'm straying onto opinion here but I'll take a chance -- does it seem like such a thing should exist? Wouldn't it be nice to just be able to drop such a thing into any application, and either write the schema yourself or allow the user to edit it? It doesn't seem so very difficult, and it would be usable in so many contexts.
I am not quite sure such a detail of personalization exists but let's give it a try:
First you should create your classes:
class Person{
private $first_name;
private $last_name;
private $adress;
public function __construct($data=array(), adress $adress=null){
foreach ($data as $cle => $valeur)
$this->$cle=$valeur;
$this->adress=$adress;
}
public function __get($property){
return $this->$property;
}
public function __set($property,$value)
{
$this->$property=$value;
}
public function all_object_properties() {
return get_object_vars($this);
}
public function all_class_properties(){
return get_class_vars(__CLASS__);
}
}
class Adress{
private $id;
private $line_1;
private $line_2;
private $suburb;
public function __construct($data=array()){
foreach ($data as $cle => $valeur)
$this->$cle=$valeur;
}
public function __get($property){
return $this->$property;
}
public function __set($property,$value)
{
$this->$property=$value;
}
public function all_object_properties() {
return get_object_vars($this);
}
public function all_class_properties(){
return get_class_vars(__CLASS__);
}
public function fill($id){
$connexion=db_connect();
$req=$connexion->prepare("SELECT * FROM adresses WHERE id=:id");
$req->execute(array('id'=>$id));
while ($row = $req->fetch(PDO::FETCH_ASSOC)){
foreach ($row as $cle => $valeur)
$this->$cle=$valeur;
}
return $this;
}
public function save(){
$connexion=db_connect();
$sql1="INSERT INTO adresses (";
$sql2=" VALUES (";
$vars=$this->all_properties();
foreach($vars as $var=>$value){
$sql1.=$var.", ";
$sql2.=":".$var.", ";
}
$sql1=substr($sql1,0,-2).")";
$sql2=substr($sql2,0,-2).")";
$sql=$sql1.$sql2;
$query=$connexion->prepare($sql);
$query->execute($vars);
if($query){
$this->id=$connexion->lastInsertId();
return true;
}else{
return false;
}
}
public function update(){
$connexion=db_connect();
$sql1="UPDATE adresses SET ";
$vars=$this->all_properties();
foreach($vars as $var=>$value){
$sql1.=$var."=".":".$var.", ";
}
$sql1=substr($sql1,0,-2)." WHERE id=:id";
$query=$connexion->prepare($sql1);
$query->execute($vars);
if($query){
return true;
}else{
return false;
}
}
}
Then you want the ability to create a form based on a file like JSON or even XML:
<forms>
<form>
<host>name_of_my_page_where_my_form_is_displayed.php</host>
<method>post</method>
<target>#</method>
<input>
<type>text</type>
<name>first_name</type>
<class>Person</class>
</input>
<input>
<type>text</type>
<name>last_name</type>
<class>Person</class>
</input>
<input>
<type>text</type>
<name>line_1</type>
<class>Adress</class>
</input>
<input>
<type>text</type>
<name>suburb</type>
<class>Adress</class>
</input>
</form>
</forms>
Here you need a function to parse and create the form:
function display_form($xml_file,$page_to_display){
$content=null;
$values=array();
$dom = new DOMDocument;
$dom->load($xml_file);
$forms=$dom->getElementsByTagName("form");
foreach($forms as $form){
$urls = $form->getElementsByTagName( "host" );
$url = $urls->item(0)->nodeValue;
if($url==htmlspecialchars($page_to_display)){
$tp_method = $form->getElementsByTagName( "method" );
$method = $tp_method->item(0)->nodeValue;
$tp_target = $form->getElementsByTagName( "target" );
$target = $tp_target->item(0)->nodeValue;
$content="<form action=".$target." method=".$method."><br/>";
$inputs=$dom->getElementsByTagName("input");
foreach($inputs as $input){
$tp = $form->getElementsByTagName( "type" );
$type = $tp->item(0)->nodeValue;
$tp = $form->getElementsByTagName( "name" );
$name = $tp->item(0)->nodeValue;
$tp = $form->getElementsByTagName( "class" );
$class = $tp->item(0)->nodeValue;
$content.="<input type=".$type." name=".$name."/><br/>";
$values[]=array("class"=>$class,"name"=>$name);
}
$content.="<input type='submit' value='Submit'/>";
}
}
return array("content"=>$content,"values"=>$values);
}
Finally in your page where the form is displayed:
<?php
$array=display_form("forms.xml",$_SERVER['REQUEST_URI']);
$content=$array['content'];
$values=$array['values'];
$classes=array();
$names=array();
foreach($values as $tab){
$class=$tab['class'];
$name=$tab['name'];
$classes[]=(!in_array($class,$classes)) ? $class : null;
$names[]=$name;
${$class}[]=$name;
}
$form_submitted=true;
foreach($names as $name){
if(!isset($_POST[$name]))
$form_submitted=false;
}
if($form_submitted){
foreach($classes as $name_class){
$var= new $name_class;
foreach(${$name_class} as $value){
$var->__set($value,$_POST[$value]);
}
$var->save();
}
}
echo $content;
In addition, you may want to create a function to fill your xml. In each classes you can use functions fill() to retrieve data for an object in the database based on their ID, save() to create a new insert in the database, or update() to update an already existent row based on the ID. There is a lot of improvement which can be done, but the general idea is here. Feel free to improve it and make yours!