routeSQL : allow to add a filter on foreign keys to limit the list of elements displayed

git-svn-id: https://svn.fournier38.fr/svn/ProgSVN/trunk@2024 bf3deb0d-5f1a-0410-827f-c0cc1f45334c
This commit is contained in:
2015-03-13 10:53:48 +00:00
parent 9628c604fd
commit 156cf358ac

View File

@@ -42,6 +42,18 @@ class routeSQL
public $path = ""; public $path = "";
/** Authentication */ /** Authentication */
public $auth = array ("email"=>"anonymous"); public $auth = array ("email"=>"anonymous");
/** Authorization object. Should allow a method named
"allow ($module, $user, $object)" which return
- NO if the object is not defined
- RO if the object is in read-only mode
- RW if the object is in read-write mode */
public $authorization = null;
/** Module name for authorization */
public $module = null;
/** Chain multiple routeSQL. Wait for an routeSQL object */
public $chained = null;
/** Chain multiple routeSQL. Wait for the foreign key */
public $chainedForeign = null;
/** The model file containing the database description */ /** The model file containing the database description */
private $model_file = ""; private $model_file = "";
/** The model class included in the model file */ /** The model class included in the model file */
@@ -60,6 +72,8 @@ class routeSQL
private $password = null; private $password = null;
/** The Options to the PDO driver if needed */ /** The Options to the PDO driver if needed */
private $driver_options = null; private $driver_options = null;
/** The Datas are protected in read-only */
private $readwriteAllowed = true;
/** Connect to the database */ /** Connect to the database */
public function __construct ($model_file, $model_class, $url_prefix, $dsn, public function __construct ($model_file, $model_class, $url_prefix, $dsn,
@@ -128,6 +142,7 @@ class routeSQL
{ {
// The maximum of links available in the paginator // The maximum of links available in the paginator
$maxClickPaginator = 10; $maxClickPaginator = 10;
$route = new route ();
$prePage = false; $prePage = false;
$postPage = false; $postPage = false;
$content = " <div class='paginatorArea'>\n"; $content = " <div class='paginatorArea'>\n";
@@ -149,7 +164,7 @@ class routeSQL
continue; continue;
} }
$displayedNumbers++; $displayedNumbers++;
$content .= " <a href='".$this->url_prefix. $content .= " <a href='".$route->baseURL().$this->url_prefix.
"?page=$i&amp;num=$num&amp;search=".urlencode ($search)."'"; "?page=$i&amp;num=$num&amp;search=".urlencode ($search)."'";
if ($page == $i) if ($page == $i)
$content .= " class='selected'"; $content .= " class='selected'";
@@ -158,7 +173,7 @@ class routeSQL
if ($displayedNumbers === 0) if ($displayedNumbers === 0)
{ {
$i = 1; $i = 1;
$content .= " <a href='".$this->url_prefix. $content .= " <a href='".$route->baseURL().$this->url_prefix.
"?page=$i&amp;num=$num&amp;search=".urlencode($search)."'"; "?page=$i&amp;num=$num&amp;search=".urlencode($search)."'";
if ($page == $i) if ($page == $i)
$content .= " class='selected'"; $content .= " class='selected'";
@@ -174,7 +189,7 @@ class routeSQL
private function addNewArea ($nbentries, $page, $num, $search) private function addNewArea ($nbentries, $page, $num, $search)
{ {
$content = ""; $content = "";
if ($this->displayActions) if ($this->displayActions && $this->readwriteAllowed)
{ {
$route = new route (); $route = new route ();
$content .= " <div class='actionExtern'>\n"; $content .= " <div class='actionExtern'>\n";
@@ -249,8 +264,18 @@ class routeSQL
/** Create the routes and the associated actions */ /** Create the routes and the associated actions */
public function routesHTML () public function routesHTML ()
{ {
// If chained routeSQL, the url_prefix must be adapted
if ($this->chained !== null)
{
if (strpos ($this->chained->url_prefix, "/{chain}/") !== false)
throw new Exception ("Chained can not have an already chained object",
500);
$this->url_prefix = $this->chained->url_prefix."/{chain}/".
$this->url_prefix;
}
/** Add HTML routes */ /** Add HTML routes */
$route = new route (); $route = new route ();
$route->allowSlashes=false;
$route->get ($this->url_prefix."/", function () use ($route) $route->get ($this->url_prefix."/", function () use ($route)
{ {
$route->redirect ("/".$this->url_prefix, ""); $route->redirect ("/".$this->url_prefix, "");
@@ -258,9 +283,16 @@ class routeSQL
$route->get ($this->url_prefix. $route->get ($this->url_prefix.
"(\?({p1}=({v1})?)(&{p2}=({v2})?(&{p3}=({v3})?)?)?)?", "(\?({p1}=({v1})?)(&{p2}=({v2})?(&{p3}=({v3})?)?)?)?",
function ($p1, $v1, $p2, $v2, $p3, $v3) use ($route) function ($p1, $v1, $p2, $v2, $p3, $v3, $chain) use ($route)
{ {
// List all the objects of the table // List all the objects of the table
if ($this->chained !== null &&
$this->chained->accessright ($chain) !== TRUE)
{
if ($this->auth["email"] === "anonymous")
throw new Exception (_("Anonymous not allowed"), 401);
throw new Exception (_("Access forbidden"), 403);
}
if ($this->accessright () !== TRUE) if ($this->accessright () !== TRUE)
{ {
if ($this->auth["email"] === "anonymous") if ($this->auth["email"] === "anonymous")
@@ -268,6 +300,10 @@ class routeSQL
throw new Exception (_("Access forbidden"), 403); throw new Exception (_("Access forbidden"), 403);
} }
if ($this->chained !== null &&
$this->chained->editright ($chain) !== true)
$this->readwriteAllowed = false;
// num is the number of elements displayed by page // num is the number of elements displayed by page
// page is the page to display // page is the page to display
// Allow the parameters to be sent in any order // Allow the parameters to be sent in any order
@@ -292,6 +328,7 @@ class routeSQL
setcookie ("page", $page, time()+3600*24*30, $this->path); setcookie ("page", $page, time()+3600*24*30, $this->path);
setcookie ("num", $num, time()+3600*24*30, $this->path); setcookie ("num", $num, time()+3600*24*30, $this->path);
setcookie ("search", $search, time()+3600*24*30, $this->path); setcookie ("search", $search, time()+3600*24*30, $this->path);
$this->url_prefix = str_replace ("{chain}", $chain, $this->url_prefix);
//echo "PAGE=$page\n"; //echo "PAGE=$page\n";
//echo "NUM=$num\n"; //echo "NUM=$num\n";
//echo "SEARCH=$search\n"; //echo "SEARCH=$search\n";
@@ -300,8 +337,13 @@ class routeSQL
$csrf = new csrf (); $csrf = new csrf ();
$token = $csrf->createToken (); $token = $csrf->createToken ();
$titles = $this->objectDB->titles (); $titles = $this->objectDB->titles ();
unset ($titles[$this->chainedForeign]);
$foreignSelect = null;
if ($this->chained !== null)
$foreignSelect = array (array ($this->chainedForeign, $chain));
if ($search === "") if ($search === "")
$datas = $this->objectDB->read (); $datas = $this->objectDB->read (null, array_keys($titles), null, null,
$foreignSelect);
else else
{ {
$criteria = array (); $criteria = array ();
@@ -318,7 +360,8 @@ class routeSQL
$s = "$s%"; $s = "$s%";
$criteria[] = array ($column, "$s", "LIKE"); $criteria[] = array ($column, "$s", "LIKE");
} }
$datas = $this->objectDB->read ($criteria, null, null, true); $datas = $this->objectDB->read ($criteria, array_keys ($titles), null,
true, $foreignSelect);
} }
$nbentries = count ($datas); $nbentries = count ($datas);
if ($num > 1000) if ($num > 1000)
@@ -390,11 +433,13 @@ class routeSQL
$content .= " <table>\n"; $content .= " <table>\n";
$content .= " <thead>\n"; $content .= " <thead>\n";
$content .= " <tr>\n"; $content .= " <tr>\n";
if ($this->displayActions && $this->actionsAtEnd === false) if ($this->readwriteAllowed && $this->displayActions &&
$this->actionsAtEnd === false)
$content .= " <th>".dgettext("domframework","Actions")."</th>\n"; $content .= " <th>".dgettext("domframework","Actions")."</th>\n";
foreach ($titles as $title) foreach ($titles as $title)
$content .= " <th>".htmlentities ($title)."</th>\n"; $content .= " <th>".htmlentities ($title)."</th>\n";
if ($this->displayActions && $this->actionsAtEnd !== false) if ($this->readwriteAllowed && $this->displayActions &&
$this->actionsAtEnd !== false)
$content .= " <th>".dgettext("domframework","Actions")."</th>\n"; $content .= " <th>".dgettext("domframework","Actions")."</th>\n";
$content .= " </tr>\n"; $content .= " </tr>\n";
$content .= " </thead>\n"; $content .= " </thead>\n";
@@ -403,7 +448,7 @@ class routeSQL
{ {
// Add one column more for actions // Add one column more for actions
$countTitles = count($titles); $countTitles = count($titles);
if ($this->displayActions) if ($this->readwriteAllowed && $this->displayActions)
$countTitles++; $countTitles++;
$content .= " <tr><td colspan='$countTitles' class='noentry'>"; $content .= " <tr><td colspan='$countTitles' class='noentry'>";
$content .= dgettext("domframework","No entry available"); $content .= dgettext("domframework","No entry available");
@@ -428,7 +473,7 @@ class routeSQL
foreach ($line as $col) foreach ($line as $col)
$content .= "<td>".htmlentities ($col)."</td>"; $content .= "<td>".htmlentities ($col)."</td>";
} }
if ($this->displayActions) if ($this->readwriteAllowed && $this->displayActions)
{ {
$content .= "<td class='action'>"; $content .= "<td class='action'>";
$content .= " <a href='".$route->baseURL().$this->url_prefix."/". $content .= " <a href='".$route->baseURL().$this->url_prefix."/".
@@ -475,9 +520,16 @@ echo $content;
}); });
$route->get ($this->url_prefix."/{id}/delete/{token}", $route->get ($this->url_prefix."/{id}/delete/{token}",
function ($id, $token) function ($id, $token, $chain)
{ {
// Delete an existing object if the token is valid // Delete an existing object if the token is valid
if ($this->chained !== null &&
$this->chained->editright ($chain) !== TRUE)
{
if ($this->auth["email"] === "anonymous")
throw new Exception (_("Anonymous not allowed"), 401);
throw new Exception (_("Access forbidden"), 403);
}
if ($this->accessright ($id) !== TRUE) if ($this->accessright ($id) !== TRUE)
{ {
if ($this->auth["email"] === "anonymous") if ($this->auth["email"] === "anonymous")
@@ -512,9 +564,16 @@ echo $content;
}); });
$route->get ($this->url_prefix."/add", function () $route->get ($this->url_prefix."/add", function ($chain)
{ {
// Add a new entry : form to be filled by the user // Add a new entry : form to be filled by the user
if ($this->chained !== null &&
$this->chained->editright ($chain) !== TRUE)
{
if ($this->auth["email"] === "anonymous")
throw new Exception (_("Anonymous not allowed"), 401);
throw new Exception (_("Access forbidden"), 403);
}
if ($this->accessright () !== TRUE) if ($this->accessright () !== TRUE)
{ {
if ($this->auth["email"] === "anonymous") if ($this->auth["email"] === "anonymous")
@@ -567,6 +626,7 @@ echo $content;
$content .= ".form-control { display: block; border-radius: 4px;padding-top: 6px; padding-right: 12px; padding-bottom: 6px; padding-left: 12px; width: 80%; }\n"; $content .= ".form-control { display: block; border-radius: 4px;padding-top: 6px; padding-right: 12px; padding-bottom: 6px; padding-left: 12px; width: 80%; }\n";
$content .= "* { box-sizing: border-box;}\n"; $content .= "* { box-sizing: border-box;}\n";
$content .= "button, input, optgroup, select, textarea { margin:0px 0px 0px 0px; }\n"; $content .= "button, input, optgroup, select, textarea { margin:0px 0px 0px 0px; }\n";
$content .= "#form .form-control[disabled], #form .form-control[readonly], #form fieldset[disabled] .form-control { cursor: not-allowed; background-color: #eee; opacity: 1; }\n";
$content .= "</style>\n"; $content .= "</style>\n";
// CSS is in edit an id too ! // CSS is in edit an id too !
} }
@@ -598,9 +658,16 @@ echo $content;
echo $content; echo $content;
}); });
$route->post ($this->url_prefix."/add", function () use ($route) $route->post ($this->url_prefix."/add", function ($chain) use ($route)
{ {
// Add a new entry : effective save of the datas // Add a new entry : effective save of the datas
if ($this->chained !== null &&
$this->chained->editright ($chain) !== TRUE)
{
if ($this->auth["email"] === "anonymous")
throw new Exception (_("Anonymous not allowed"), 401);
throw new Exception (_("Access forbidden"), 403);
}
if ($this->accessright () !== TRUE) if ($this->accessright () !== TRUE)
{ {
if ($this->auth["email"] === "anonymous") if ($this->auth["email"] === "anonymous")
@@ -649,16 +716,27 @@ echo $content;
}); });
$route->get ($this->url_prefix."/{id}", function ($id) $route->get ($this->url_prefix."/{id}", function ($id, $chain)
{ {
// List the details of one existing object // List the details of one existing object
if ($this->chained !== null &&
$this->chained->accessright ($chain) !== TRUE)
{
if ($this->auth["email"] === "anonymous")
throw new Exception (_("Anonymous not allowed"), 401);
throw new Exception (_("Access forbidden"), 403);
}
if ($this->accessright ($id) !== TRUE) if ($this->accessright ($id) !== TRUE)
{ {
if ($this->auth["email"] === "anonymous") if ($this->auth["email"] === "anonymous")
throw new Exception (_("Anonymous not allowed"), 401); throw new Exception (_("Anonymous not allowed"), 401);
throw new Exception (_("Access forbidden"), 403); throw new Exception (_("Access forbidden"), 403);
} }
$editright = $this->editright ($id); if ($this->chained !== null &&
$this->chained->editright ($chain) !== true)
$this->readwriteAllowed = false;
if ($this->readwriteAllowed === true)
$this->readwriteAllowed = $this->editright ($id);
$readonly = $this->readonly ($id); $readonly = $this->readonly ($id);
$this->connect(); $this->connect();
@@ -703,6 +781,7 @@ echo $content;
$content .= ".form-control { display: block; border-radius: 4px;padding-top: 6px; padding-right: 12px; padding-bottom: 6px; padding-left: 12px; width: 80%; }\n"; $content .= ".form-control { display: block; border-radius: 4px;padding-top: 6px; padding-right: 12px; padding-bottom: 6px; padding-left: 12px; width: 80%; }\n";
$content .= "* { box-sizing: border-box;}\n"; $content .= "* { box-sizing: border-box;}\n";
$content .= "button, input, optgroup, select, textarea { margin:0px 0px 0px 0px; }\n"; $content .= "button, input, optgroup, select, textarea { margin:0px 0px 0px 0px; }\n";
$content .= "#form .form-control[disabled], #form .form-control[readonly], #form fieldset[disabled] .form-control { cursor: not-allowed; background-color: #eee; opacity: 1; }\n";
$content .= "</style>\n"; $content .= "</style>\n";
// CSS is in add too ! // CSS is in add too !
} }
@@ -720,13 +799,13 @@ echo $content;
$field->mandatory = true; $field->mandatory = true;
if (in_array ("autoincrement", $this->objectDB->fields[$key])) if (in_array ("autoincrement", $this->objectDB->fields[$key]))
$field->type = "hidden"; $field->type = "hidden";
if ($readonly === true || $editright === false) if ($readonly === true || $this->readwriteAllowed === false)
$field->readonly = true; $field->readonly = true;
$fields[] = $field; $fields[] = $field;
unset ($field); unset ($field);
} }
if ($readonly === false && $editright === true) if ($readonly === false && $this->readwriteAllowed === true)
{ {
$field = new formfield ("submit", _("Save the datas")); $field = new formfield ("submit", _("Save the datas"));
$field->defaults = _("Save the datas"); $field->defaults = _("Save the datas");
@@ -739,9 +818,16 @@ echo $content;
echo $content; echo $content;
}); });
$route->post ($this->url_prefix."/{id}", function ($id) use ($route) $route->post ($this->url_prefix."/{id}", function ($id, $chain) use ($route)
{ {
// Save the details of one existing object // Save the details of one existing object
if ($this->chained !== null &&
$this->chained->editright ($chain) !== TRUE)
{
if ($this->auth["email"] === "anonymous")
throw new Exception (_("Anonymous not allowed"), 401);
throw new Exception (_("Access forbidden"), 403);
}
if ($this->accessright ($id) !== TRUE) if ($this->accessright ($id) !== TRUE)
{ {
if ($this->auth["email"] === "anonymous") if ($this->auth["email"] === "anonymous")
@@ -800,22 +886,53 @@ echo $content;
/** Authorization : Return TRUE if the user right allow to see the datas /** Authorization : Return TRUE if the user right allow to see the datas
Return FALSE else */ Return FALSE else */
public function accessright () public function accessright ($id=null)
{ {
// echo "accessright=".var_export ($id, TRUE)." for ".
// var_export($this->model_class, TRUE)."\n";
if ($this->authorization !== null)
{
$result = $this->authorization->allow ($this->module,
$this->auth["email"], "/$id");
// echo "RESULT=$result\n";
if ($result === "RO") return TRUE;
if ($result === "RW") return TRUE;
return FALSE;
}
return TRUE; return TRUE;
} }
/** Authorization : Return TRUE if the user right allow to edit the datas /** Authorization : Return TRUE if the user right allow to edit the datas
Return FALSE else */ Return FALSE else */
public function editright () public function editright ($id=null)
{ {
// echo "editright=".var_export ($id, TRUE)." for ".
// var_export($this->model_class, TRUE)."\n";
if ($this->authorization !== null)
{
$result = $this->authorization->allow ($this->module,
$this->auth["email"], "/$id");
// echo "RESULT=$result\n";
if ($result === "RW") return TRUE;
return FALSE;
}
return TRUE; return TRUE;
} }
/** Authorization : Return TRUE if the $id is in READONLY for the user or /** Authorization : Return TRUE if the $id is in READONLY for the user or
FALSE if the user have the RW rights */ FALSE if the user have the RW rights */
public function readonly () public function readonly ($id=null)
{ {
// echo "readonly=".var_export ($id, TRUE)." for ".
// var_export($this->model_class, TRUE)."\n";
if ($this->authorization !== null)
{
$result = $this->authorization->allow ($this->module,
$this->auth["email"], "/$id");
// echo "RESULT=$result\n";
if ($result === "RO") return TRUE;
return FALSE;
}
return FALSE; return FALSE;
} }
} }