Files
DomFramework/routeSQL.php
2015-03-11 10:49:30 +00:00

453 lines
16 KiB
PHP

<?php
/** DomFramework
@package domframework
@author Dominique Fournier <dominique@fournier38.fr> */
require_once ("domframework/route.php");
require_once ("domframework/form.php");
require_once ("domframework/renderer.php");
error_reporting (E_ALL);
/** Automatic Routing for SQL database
Allow to do CRUD on datas with only one line in index.php */
class routeSQL
{
/** Display the Actions column in list of entries */
public $displayActions = true;
/** Do a confirmation in javascript before deleting entry */
public $deleteConfirm = true;
/** Push the actions buttons at end of line */
public $actionsAtEnd = false;
/** The Text to Delete */
public $textDelete = "";
/** The Text to Edit */
public $textEdit = "";
/** The model file containing the database description */
private $model_file = "";
/** The model class included in the model file */
private $model_class = "";
/** The prefix to be used in the URL. Should be the end of $model_file
Ex : if $model_file = models/model_zone.php, the url_prefix should be
zone */
private $url_prefix = "";
/** The SQL object created */
private $objectDB = null;
/** The DSN to connect to the database */
private $dsn = null;
/** The Username to connect to the database */
private $username = null;
/** The Password to connect to the database */
private $password = null;
/** The Options to the PDO driver if needed */
private $driver_options = null;
/** Connect to the database */
public function __construct ($model_file, $model_class, $url_prefix, $dsn,
$username = null, $password = null, $driver_options = null)
{
$this->model_file = $model_file;
$this->model_class = $model_class;
$this->url_prefix = $url_prefix;
$this->dsn = $dsn;
$this->username = $username;
$this->password = $password;
$this->driver_options = $driver_options;
$this->textDelete = dgettext("domframework","Delete");
$this->textEdit = dgettext("domframework","Edit");
}
/** Connect to the database */
private function connect ()
{
include "models/$this->model_file";
$this->objectDB = new $this->model_class ($this->dsn, $this->username,
$this->password, $this->driver_options);
}
/** Display the flash informations if no flash view is available */
private function showflash ()
{
$dataflash = "";
if (file_exists ("views/flash.php"))
require ("views/flash.php");
else
{
if (isset ($_SESSION["renderer"]["flash"]))
{
foreach ($_SESSION["renderer"]["flash"] as $flash)
{
$dataflash .= "<div class='alert ";
switch ($flash[0])
{
case 4: $dataflash .= "alert-danger";$alert = _("Error!");break;
case 3: $dataflash .= "alert-warning";$alert = _("Warning!");break;
case 2: $dataflash .= "alert-info";$alert = _("Info :");break;
case 1: $dataflash .= "alert-success";$alert = _("Success : ");break;
}
$dataflash .= " alert-dismissable'>\n";
$dataflash .= "<strong>$alert</strong> ".$flash[1]."\n";
$dataflash .= "</div>\n";
}
unset ($_SESSION["renderer"]["flash"]);
}
}
return $dataflash;
}
/** Display a paginator
$nbentries is the total number of elements
num is the number of elements displayed by page
page is the page to display */
private function paginator ($nbentries, $page, $num)
{
// The maximum of links available in the paginator
$maxClickPaginator = 10;
$prePage = false;
$postPage = false;
$content = "<div>";
$displayedNumbers = 0;
for ($i = 1 ; $i < ($nbentries/$num) ; $i++)
{
if ($i < ($page - $maxClickPaginator/2))
{
if ($prePage === false)
$content .= "... ";
$prePage = true;
continue;
}
if ($displayedNumbers >= $maxClickPaginator)
{
if ($postPage === false)
$content .= "... ";
$postPage = true;
continue;
}
$displayedNumbers++;
$content .= "<a href='".$this->url_prefix."?page=$i&amp;num=$num'";
if ($page == $i)
$content .= "style='background-color:#FFFF66;'";
$content .= ">$i</a> ";
}
$content .= "</div>";
return $content;
}
/** Create the routes and the associated actions */
public function routes ()
{
/** Add HTML routes */
$route = new route ();
$route->get ($this->url_prefix."/", function () use ($route)
{
$route->redirect ("/".$this->url_prefix, "");
});
$route->get ($this->url_prefix."(\?({p1}={v1})(&{p2}={v2})?)?",
function ($p1, $v1, $p2, $v2) use ($route)
{
// LIST ALL THE OBJECTS OF THE TABLE
// num is the number of elements displayed by page
// page is the page to display
// Allow the parameters to be sent in any order
if ($p1 === "num") $num = $v1;
if ($p2 === "num") $num = $v2;
if ($p1 === "page") $page = $v1;
if ($p2 === "page") $page = $v2;
$this->connect();
$csrf = new csrf ();
$token = $csrf->createToken ();
$datas = $this->objectDB->read ();
$titles = $this->objectDB->titles ();
if ($page === null || $page === "") $page = 1;
if ($num === null || $num === "") $num = 10;
$page = intval ($page);
$num = intval ($num);
if ($num > 1000)
$route->redirect ("/".$this->url_prefix."?page=$page&num=1000", "");
if ($page < 1)
$route->redirect ("/".$this->url_prefix."?page=1&num=$num", "");
// Push on the last page if the values are too high
if ($page*$num > count ($datas))
{
$maxPage = intval(count ($datas)/$num);
$route->redirect ("/".$this->url_prefix."?page=$maxPage&num=$num", "");
}
$content = $this->showflash ();
if ($this->displayActions)
$content .= "<a href='".$route->baseURL().$this->url_prefix."/add'>".
dgettext("domframework","Add new entry")."</a>\n";
$content .= $this->paginator(count ($datas), $page, $num);
$content .= "<table>\n";
$content .= " <thead>\n";
if ($this->displayActions && $this->actionsAtEnd === false)
$content .= " <th>".dgettext("domframework","Actions")."</th>\n";
foreach ($titles as $title)
$content .= " <th>".htmlentities ($title)."</th>\n";
if ($this->displayActions && $this->actionsAtEnd !== false)
$content .= " <th>".dgettext("domframework","Actions")."</th>\n";
$content .= " </thead>\n";
$content .= " <tbody>\n";
if (count ($datas) === 0)
{
$content .= " <tr><td colspan='".count($titles)."'>";
$content .= dgettext("domframework","No entry available");
$content .= "</td></tr>\n";
}
else
{
$i = 1;
foreach ($datas as $line)
{
if ($i <= (($page-1)*$num) || $i > (($page-1)*$num + $num))
{
$i++;
continue;
}
$content .= " <tr>";
if ($this->displayActions && $this->actionsAtEnd === false)
{
$content .= "<td>";
$content .= " <a href='".$route->baseURL().$this->url_prefix."/".
$line[$this->objectDB->primary]."'>".
$this->textEdit."</a>";
$content .= " <a href='".$route->baseURL().$this->url_prefix."/".
$line[$this->objectDB->primary]."/delete/$token'";
if ($this->deleteConfirm)
$content .= " onclick=\"return confirm('".
dgettext("domframework",
"Are you sure to delete this entry?")."')\"";
$content .= ">".$this->textDelete."</a>";
$content .= "</td>";
}
foreach ($line as $col)
$content .= "<td>".htmlentities ($col)."</td>";
if ($this->displayActions && $this->actionsAtEnd !== false)
{
$content .= "<td>";
$content .= " <a href='".$route->baseURL().$this->url_prefix."/".
$line[$this->objectDB->primary]."'>".
$this->textEdit."</a>";
$content .= " <a href='".$route->baseURL().$this->url_prefix."/".
$line[$this->objectDB->primary]."/delete/$token'";
if ($this->deleteConfirm)
$content .= " onclick=\"return confirm('".
dgettext("domframework",
"Are you sure to delete this entry?")."')\"";
$content .= ">".$this->textDelete."</a>";
$content .= "</td>";
}
$content .= "</tr>\n";
$i++;
}
}
$content .= " </tbody>\n";
$content .= "</table>\n";
echo $content;
});
$route->get ($this->url_prefix."/{id}/delete/{token}",
function ($id, $token)
{
echo "DELETE AN EXISTING OBJECT IF THE TOKEN IS VALID !";
$this->connect();
$csrf = new csrf ();
$renderer = new renderer ();
$route = new route ();
try
{
$csrf->checkToken ($token);
$this->objectDB->delete ($id);
$route->redirect ("/".$this->url_prefix, "");
}
catch (Exception $e)
{
$renderer->flash ("ERROR", $e->getMessage());
$route->redirect ("/".$this->url_prefix, "");
}
});
$route->get ($this->url_prefix."/add", function ()
{
// Add a new entry : form to be filled by the user
$this->connect();
$content = $this->showflash ();
$values = array ();
$errors = array();
$titles = $this->objectDB->titles ();
if (isset ($_SESSION["domframework"]["routeSQL"]["errors"]))
{
$errors = $_SESSION["domframework"]["routeSQL"]["errors"];
unset ($_SESSION["domframework"]["routeSQL"]["errors"]);
}
if (isset ($_SESSION["domframework"]["routeSQL"]["values"]))
{
$values = $_SESSION["domframework"]["routeSQL"]["values"];
unset ($_SESSION["domframework"]["routeSQL"]["values"]);
}
$f = new form ();
$fields = array ();
foreach ($titles as $key=>$val)
{
$field = new formfield ($key, $val);
if (! isset ($this->objectDB->fields[$key]))
throw new Exception (sprintf (dgettext("domframework",
"Field '%s' (defined in titles) not found in fields"),
$key), 500);
if (in_array ("not null", $this->objectDB->fields[$key]))
$field->mandatory = true;
if (in_array ("autoincrement", $this->objectDB->fields[$key]))
$field->type = "hidden";
$fields[] = $field;
unset ($field);
}
$field = new formfield ("submit", _("Save the zone"));
$field->defaults = _("Save the zone");
$field->type = "submit";
$fields[] = $field;
unset ($field);
$f->fields ($fields);
$content .= $f->printHTML ("post", $values, $errors);
echo $content;
});
$route->post ($this->url_prefix."/add", function () use ($route)
{
// Add a new entry : effective save of the datas
$this->connect();
$f = new form ();
$values = $f->values ();
$errors = $this->objectDB->verify ($values);
if (count ($errors) == 0)
{
try
{
$this->objectDB->insert ($values);
$renderer = new renderer ();
$renderer->flash ("SUCCESS", _("Creation done"));
$route->redirect ("/".$this->url_prefix, "");
}
catch (Exception $e)
{
$renderer = new renderer ();
$renderer->flash ("ERROR", $e->getMessage ());
}
}
else
{
$renderer = new renderer ();
foreach ($errors as $error)
$renderer->flash (strtoupper ($error[0]), $error[1]);
}
// If errors : save them and redirect to the page of editing to be
// corrected
$_SESSION["domframework"]["routeSQL"]["errors"] = $errors;
$_SESSION["domframework"]["routeSQL"]["values"] = $values;
$route->redirect ("/".$this->url_prefix."/add", "");
});
$route->get ($this->url_prefix."/{id}", function ($id)
{
// LIST THE DETAILS OF ONE EXISTING OBJECT !
$this->connect();
$content = $this->showflash ();
$values = array ();
$errors = array();
$titles = $this->objectDB->titles ();
$values = $this->objectDB->read (array (array ($this->objectDB->primary,
$id)));
if (count ($values) === 0)
throw new Exception (dgettext("domframework", "Object not found"), 404);
$values = $values[0];
if (isset ($_SESSION["domframework"]["routeSQL"]["errors"]))
{
$errors = $_SESSION["domframework"]["routeSQL"]["errors"];
unset ($_SESSION["domframework"]["routeSQL"]["errors"]);
}
if (isset ($_SESSION["domframework"]["routeSQL"]["values"]))
{
$values = $_SESSION["domframework"]["routeSQL"]["values"];
unset ($_SESSION["domframework"]["routeSQL"]["values"]);
}
$f = new form ();
$fields = array ();
foreach ($titles as $key=>$val)
{
$field = new formfield ($key, $val);
if (! isset ($this->objectDB->fields[$key]))
throw new Exception (sprintf (dgettext("domframework",
"Field '%s' (defined in titles) not found in fields"),
$key), 500);
if (in_array ("not null", $this->objectDB->fields[$key]))
$field->mandatory = true;
if (in_array ("autoincrement", $this->objectDB->fields[$key]))
$field->type = "hidden";
$fields[] = $field;
unset ($field);
}
$field = new formfield ("submit", _("Save the zone"));
$field->defaults = _("Save the zone");
$field->type = "submit";
$fields[] = $field;
unset ($field);
$f->fields ($fields);
$content .= $f->printHTML ("post", $values, $errors);
echo $content;
});
$route->post ($this->url_prefix."/{id}", function ($id) use ($route)
{
// SAVE THE DETAILS OF ONE EXISTING OBJECT !
$this->connect();
$oldvalues = $this->objectDB->read (array (array
($this->objectDB->primary, $id)));
if (count ($oldvalues) === 0)
throw new Exception (dgettext("domframework", "Object not found"), 404);
$oldvalues = $oldvalues[0];
$f = new form ();
$values = $f->values ();
if ($values[$this->objectDB->primary] !== $id)
throw new Exception (dgettext("domframework",
"Can not change the primary key"), 403);
$errors = $this->objectDB->verify ($values, $id);
if (count ($errors) == 0)
{
try
{
$this->objectDB->update ($id, $values);
$renderer = new renderer ();
$renderer->flash ("SUCCESS", _("Update done"));
$route->redirect ("/".$this->url_prefix, "");
}
catch (Exception $e)
{
$renderer = new renderer ();
$renderer->flash ("ERROR", $e->getMessage ());
}
}
else
{
$renderer = new renderer ();
foreach ($errors as $error)
$renderer->flash (strtoupper ($error[0]), $error[1]);
}
// If errors : save them and redirect to the page of editing to be
// corrected
$_SESSION["domframework"]["routeSQL"]["errors"] = $errors;
$_SESSION["domframework"]["routeSQL"]["values"] = $values;
$route->redirect ("/".$this->url_prefix."/$id", "");
});
echo "Route not found";
}
}