2382 lines
93 KiB
PHP
2382 lines
93 KiB
PHP
<?php
|
|
|
|
/**
|
|
* DomFramework
|
|
* @package domframework
|
|
* @author Dominique Fournier <dominique@fournier38.fr>
|
|
* @license BSD
|
|
*/
|
|
|
|
namespace Domframework;
|
|
|
|
/**
|
|
* Automatic Routing for SQL database
|
|
* Allow to do CRUD on data with only one line in index.php
|
|
*/
|
|
class RouteSQL
|
|
{
|
|
/**
|
|
* Activate the debug
|
|
*/
|
|
public $debug = 0;
|
|
/**
|
|
* 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 = "";
|
|
/**
|
|
* enable internal CSS
|
|
*/
|
|
public $enableInternalCSS = true;
|
|
/**
|
|
* Definition of the position in top bar at left
|
|
* Allowed : addNew numberEntryByDisplay search information paginator
|
|
*/
|
|
public $topBarLeft = ["addNew", "numberEntryByDisplay"];
|
|
/**
|
|
* Definition of the position in top bar at right
|
|
* Allowed : addNew numberEntryByDisplay search information paginator
|
|
*/
|
|
public $topBarRight = ["search"];
|
|
/**
|
|
* Definition of the position in bottom bar at left
|
|
* Allowed : addNew numberEntryByDisplay search information paginator
|
|
*/
|
|
public $bottomBarLeft = ["information"];
|
|
/**
|
|
* Definition of the position in bottom bar at right
|
|
* Allowed : addNew numberEntryByDisplay search information paginator
|
|
*/
|
|
public $bottomBarRight = ["paginator"];
|
|
/**
|
|
* The cookie path used to determine the old parameters
|
|
* It is automatically generated with the URL
|
|
*/
|
|
public $path = "";
|
|
/**
|
|
* Authentication for HTML part
|
|
*/
|
|
public $authHTML = ["email" => "anonymous"];
|
|
/**
|
|
* Authentication for REST part
|
|
*/
|
|
public $authREST = ["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;
|
|
/**
|
|
* Allow one or multiple links by entry in the list
|
|
* The array must be of the form array ("linkname"=>, "icon"=>)
|
|
* icon is optional and the linkname is used if it is not provided
|
|
*/
|
|
public $internalLinks = [];
|
|
/**
|
|
* The renderer class to use for HTML pages
|
|
*/
|
|
public $rendererHTMLclass = false;
|
|
/**
|
|
* The renderer method to use for HTML pages
|
|
*/
|
|
public $rendererHTMLmethod = false;
|
|
/**
|
|
* The layout HTML to use for HTML pages
|
|
*/
|
|
public $rendererHTMLlayout = false;
|
|
/**
|
|
* The extensions allowed in REST
|
|
*/
|
|
public $extensionsAllowed = ["json", "xml"];
|
|
|
|
/**
|
|
* 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;
|
|
/**
|
|
* The Datas are protected in read-only
|
|
*/
|
|
private $readwriteAllowed = true;
|
|
|
|
/**
|
|
* Connect to the database
|
|
* @param string $model_file The model file containing the database
|
|
* description
|
|
* @param string $model_class The model class included in the model file
|
|
* @param string $url_prefix The prefix to be used in the URL. Should be the
|
|
* end of $model_file
|
|
* @param string $dsn The DSN to connect to the database
|
|
* @param string $username The username to connect to the database
|
|
* @param string $password The password to connect to the database
|
|
* @param array|null $driver_options The PDO driver options
|
|
*/
|
|
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 = "❌";
|
|
$this->textEdit = "✎";
|
|
$pos = strpos($_SERVER["REQUEST_URI"], "?");
|
|
if ($pos === false) {
|
|
$this->path = $_SERVER["REQUEST_URI"];
|
|
} else {
|
|
$this->path = substr($_SERVER["REQUEST_URI"], 0, $pos);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 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 information 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) {
|
|
$alert = "";
|
|
$dataflash .= "<div class='alert ";
|
|
switch ($flash[0]) {
|
|
case 4:
|
|
$dataflash .= "alert-danger";
|
|
$alert = dgettext("domframework", "Error!");
|
|
break;
|
|
case 3:
|
|
$dataflash .= "alert-warning";
|
|
$alert = dgettext("domframework", "Warning!");
|
|
break;
|
|
case 2:
|
|
$dataflash .= "alert-info";
|
|
$alert = dgettext("domframework", "Info:");
|
|
break;
|
|
case 1:
|
|
$dataflash .= "alert-success";
|
|
$alert = dgettext("domframework", "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
|
|
* @param integer $nbentries The number of entries to display
|
|
* @param integer $page The page number to display
|
|
* @param integer $num ???
|
|
* @param string $search The search query
|
|
*/
|
|
private function paginatorArea($nbentries, $page, $num, $search)
|
|
{
|
|
// The maximum of links available in the paginator
|
|
$maxClickPaginator = 10;
|
|
$route = new Route();
|
|
$prePage = false;
|
|
$postPage = false;
|
|
$content = " <div class='paginatorArea'>\n";
|
|
$content .= "<ul class='paginatorArea'>\n";
|
|
$displayedNumbers = 0;
|
|
for ($i = 1; $i < (1 + $nbentries / ($num)); $i++) {
|
|
$content .= "<li";
|
|
if ($page == $i) {
|
|
$content .= " class='selected'";
|
|
}
|
|
$content .= ">";
|
|
if ($i < ($page - $maxClickPaginator / 2)) {
|
|
if ($prePage === false) {
|
|
$content .= " ...\n";
|
|
}
|
|
$content .= "</li>\n";
|
|
$prePage = true;
|
|
continue;
|
|
}
|
|
if ($displayedNumbers >= $maxClickPaginator) {
|
|
if ($postPage === false) {
|
|
$content .= " ...\n";
|
|
}
|
|
$content .= "</li>\n";
|
|
$postPage = true;
|
|
continue;
|
|
}
|
|
$displayedNumbers++;
|
|
$content .= " <a href='" . $route->baseURL() . $this->url_prefix .
|
|
"?page=$i&num=$num&search=" . urlencode($search) . "'";
|
|
if ($page == $i) {
|
|
$content .= " class='selected'";
|
|
}
|
|
$content .= ">$i</a>\n";
|
|
$content .= "</li>\n";
|
|
}
|
|
if ($displayedNumbers === 0) {
|
|
$content .= "<li class='selected'>";
|
|
$i = 1;
|
|
$content .= " <a href='" . $route->baseURL() . $this->url_prefix .
|
|
"?page=$i&num=$num&search=" . urlencode($search) . "'";
|
|
if ($page == $i) {
|
|
$content .= " class='selected'";
|
|
}
|
|
$content .= ">$i</a>\n";
|
|
$content .= "</li>\n";
|
|
}
|
|
$content .= " </ul>\n";
|
|
$content .= " </div>\n";
|
|
return $content;
|
|
}
|
|
|
|
/**
|
|
* Display the actions buttons outside of the table (actually, juste the
|
|
* 'Add new entry' button
|
|
* @param integer $nbentries The number of entries
|
|
* @param integer $page The page number
|
|
* @param integer $num ???
|
|
* @param string $search The search query
|
|
*/
|
|
private function addNewArea($nbentries, $page, $num, $search)
|
|
{
|
|
$content = "";
|
|
if ($this->displayActions && $this->readwriteAllowed) {
|
|
$route = new Route();
|
|
$content .= " <div class='actionExtern'>\n";
|
|
$content .= " <a href='" . $route->baseURL() . $this->url_prefix . "/add'>"
|
|
. dgettext("domframework", "Add new entry") . "</a>\n";
|
|
$content .= " </div>\n";
|
|
}
|
|
return $content;
|
|
}
|
|
|
|
/**
|
|
* Display the select list to choose the number of displayed entries
|
|
* @param integer $nbentries The number of entries
|
|
* @param integer $page The page number
|
|
* @param integer $num ???
|
|
* @param string $search The search query
|
|
*/
|
|
private function numberEntryByDisplayArea($nbentries, $page, $num, $search)
|
|
{
|
|
$route = new Route();
|
|
$content = "";
|
|
$content .= " <div class='numberEntryByDisplayArea'>\n";
|
|
$content .= " <form method='get' action='" . $route->baseURL() .
|
|
$this->url_prefix . "'>\n";
|
|
$content .= " <select name='num' onchange='this.form.submit()' >\n";
|
|
$list = [10, 20, 50, 100, 200, 500, 1000];
|
|
foreach ($list as $element) {
|
|
$content .= " <option ";
|
|
if ($element == $num) {
|
|
$content .= "selected='selected'";
|
|
}
|
|
$content .= ">$element</option>\n";
|
|
}
|
|
$content .= " </select>\n";
|
|
$content .= " " . dgettext("domframework", "elements") . "\n";
|
|
$content .= " </form>\n";
|
|
$content .= " </div>\n";
|
|
return $content;
|
|
}
|
|
|
|
/**
|
|
* Display the search area
|
|
* @param integer $nbentries The number of entries
|
|
* @param integer $page The page number
|
|
* @param integer $num ???
|
|
* @param string $search The search query
|
|
*/
|
|
private function searchArea($nbentries, $page, $num, $search)
|
|
{
|
|
$route = new Route();
|
|
$content = "";
|
|
$content .= " <div class='searchArea'>\n";
|
|
$content .= " <form method='get' action='" . $route->baseURL() .
|
|
$this->url_prefix . "'>\n";
|
|
$content .= " " . dgettext("domframework", "Search:");
|
|
$content .= " <input type='text' name='search' value='" .
|
|
htmlentities($search, ENT_QUOTES) . "'/>\n";
|
|
$content .= " </form>\n";
|
|
$content .= " </div>\n";
|
|
return $content;
|
|
}
|
|
|
|
/**
|
|
* Display the information
|
|
* @param integer $nbentries The number of entries
|
|
* @param integer $page The page number
|
|
* @param integer $num ???
|
|
* @param string $search The search query
|
|
*/
|
|
private function informationArea($nbentries, $page, $num, $search)
|
|
{
|
|
$content = "";
|
|
$content .= " <div class='informationArea'>\n";
|
|
$message = dgettext(
|
|
"domframework",
|
|
"Display the element {FIRST} to {LAST} on {COUNT} elements"
|
|
);
|
|
if ($nbentries === 0) {
|
|
$message = str_replace("{FIRST}", 0, $message);
|
|
} else {
|
|
$message = str_replace("{FIRST}", 1 + ($num * ($page - 1)), $message);
|
|
}
|
|
if ($nbentries < ($num * $page)) {
|
|
$message = str_replace("{LAST}", $nbentries, $message);
|
|
} else {
|
|
$message = str_replace("{LAST}", ($num * $page), $message);
|
|
}
|
|
$message = str_replace("{COUNT}", $nbentries, $message);
|
|
$content .= $message;
|
|
$content .= " </div>\n";
|
|
return $content;
|
|
}
|
|
|
|
/**
|
|
* Create the routes for REST pages and the associated actions
|
|
*/
|
|
public function routesREST()
|
|
{
|
|
$route = new Route();
|
|
$route->debug = $this->debug;
|
|
;
|
|
$route->allowSlashes = false;
|
|
$route->get(
|
|
"rest/" . $this->url_prefix . "(\.{extension})?" .
|
|
"(\?({p1}=({v1})?)(&{p2}=({v2})?(&{p3}=({v3})?)?)?)?",
|
|
function ($extension, $p1, $v1, $p2, $v2, $p3, $v3, $chain = null) {
|
|
if ($this->chained !== null) {
|
|
if (
|
|
$this->chained->accessright($this->authREST["email"], $chain) !==
|
|
true
|
|
) {
|
|
if ($this->authREST["email"] === "anonymous") {
|
|
throw new \Exception(dgettext(
|
|
"domframework",
|
|
"Anonymous not allowed"
|
|
), 401);
|
|
}
|
|
throw new \Exception(dgettext(
|
|
"domframework",
|
|
"Access forbidden"
|
|
), 403);
|
|
}
|
|
$this->chained->connect();
|
|
// $chainedValues are the information associated to the $chain
|
|
$chainedValues = $this->chained->keyexists($chain);
|
|
if ($chainedValues === false) {
|
|
throw new \Exception(dgettext(
|
|
"domframework",
|
|
"Object not found"
|
|
), 404);
|
|
}
|
|
}
|
|
if ($this->accessright($this->authREST["email"]) !== true) {
|
|
if ($this->authREST["email"] === "anonymous") {
|
|
throw new \Exception(dgettext(
|
|
"domframework",
|
|
"Anonymous not allowed"
|
|
), 401);
|
|
}
|
|
throw new \Exception(dgettext(
|
|
"domframework",
|
|
"Access forbidden"
|
|
), 403);
|
|
}
|
|
|
|
if ($p1 === "search") {
|
|
$search = $v1;
|
|
}
|
|
if ($p2 === "search") {
|
|
$search = $v2;
|
|
}
|
|
if ($p3 === "search") {
|
|
$search = $v3;
|
|
}
|
|
if (!isset($search) || $search === null || $search === "") {
|
|
$search = "";
|
|
}
|
|
if (!isset($extension) || $extension === null || $extension === "") {
|
|
$extension = reset($this->extensionsAllowed);
|
|
}
|
|
if (!in_array($extension, $this->extensionsAllowed, true)) {
|
|
throw new \Exception(dgettext(
|
|
"domframework",
|
|
"Extension not allowed"
|
|
), 403);
|
|
}
|
|
$search = rawurldecode($search);
|
|
$this->connect();
|
|
$titles = $this->objectDB->titles();
|
|
unset($titles[$this->chainedForeign]);
|
|
$foreignSelect = null;
|
|
if ($this->chained !== null) {
|
|
$foreignSelect = [[$this->chainedForeign, $chain]];
|
|
}
|
|
if ($search === "") {
|
|
$data = $this->objectDB->read(
|
|
null,
|
|
array_keys($titles),
|
|
null,
|
|
null,
|
|
$foreignSelect
|
|
);
|
|
} else {
|
|
$criteria = [];
|
|
foreach (array_keys($titles) as $column) {
|
|
$s = $search;
|
|
if ($search[0] === "^") {
|
|
$s = substr($s, 1);
|
|
} else {
|
|
$s = "%$s";
|
|
}
|
|
if (substr($search, -1) === "$") {
|
|
$s = substr($s, 0, -1);
|
|
} else {
|
|
$s = "$s%";
|
|
}
|
|
$criteria[] = [$column, "$s", "LIKE"];
|
|
}
|
|
$data = $this->objectDB->read(
|
|
$criteria,
|
|
array_keys($titles),
|
|
null,
|
|
true,
|
|
$foreignSelect
|
|
);
|
|
}
|
|
// Limiting access to data only to data with read access right
|
|
foreach ($data as $key => $vals) {
|
|
if (
|
|
$this->accessright(
|
|
$this->authHTML["email"],
|
|
$vals[$this->objectDB->primary]
|
|
) !== true
|
|
) {
|
|
unset($data[$key]);
|
|
}
|
|
}
|
|
|
|
$this->renderrest($extension, $data);
|
|
}
|
|
);
|
|
|
|
$route->post(
|
|
"rest/" . $this->url_prefix . "(\.{extension})?",
|
|
function ($extension, $chain = null) {
|
|
if ($this->chained !== null) {
|
|
if (
|
|
$this->chained->editright($this->authREST["email"], $chain) !==
|
|
true
|
|
) {
|
|
if ($this->authREST["email"] === "anonymous") {
|
|
throw new \Exception(dgettext(
|
|
"domframework",
|
|
"Anonymous not allowed"
|
|
), 401);
|
|
}
|
|
throw new \Exception(
|
|
dgettext("domframework", "Access forbidden"),
|
|
403
|
|
);
|
|
}
|
|
$this->chained->connect();
|
|
// $chainedvalues are the information associated to the $chain
|
|
$chainedvalues = $this->chained->keyexists($chain);
|
|
if ($chainedvalues === false) {
|
|
throw new \Exception(dgettext(
|
|
"domframework",
|
|
"Object not found"
|
|
), 404);
|
|
}
|
|
}
|
|
if ($this->accessright($this->authREST["email"]) !== true) {
|
|
if ($this->authREST["email"] === "anonymous") {
|
|
throw new \Exception(dgettext(
|
|
"domframework",
|
|
"Anonymous not allowed"
|
|
), 401);
|
|
}
|
|
throw new \Exception(
|
|
dgettext("domframework", "Access forbidden"),
|
|
403
|
|
);
|
|
}
|
|
if ($this->editright($this->authREST["email"]) !== true) {
|
|
if ($this->authREST["email"] === "anonymous") {
|
|
throw new \Exception(dgettext(
|
|
"domframework",
|
|
"Anonymous not allowed"
|
|
), 401);
|
|
}
|
|
throw new \Exception(
|
|
dgettext("domframework", "Access forbidden"),
|
|
403
|
|
);
|
|
}
|
|
if ($this->readonly($this->authREST["email"]) === true) {
|
|
throw new \Exception(
|
|
dgettext("domframework", "Access forbidden"),
|
|
403
|
|
);
|
|
}
|
|
if (!isset($extension) || $extension === null || $extension === "") {
|
|
$extension = reset($this->extensionsAllowed);
|
|
}
|
|
if (!in_array($extension, $this->extensionsAllowed, true)) {
|
|
throw new \Exception(dgettext(
|
|
"domframework",
|
|
"Extension not allowed"
|
|
), 403);
|
|
}
|
|
$this->connect();
|
|
$values = $_POST;
|
|
$errorsChain = [];
|
|
if (
|
|
$this->chainedForeign !== null &&
|
|
isset($values[$this->chainedForeign]) &&
|
|
$values[$this->chainedForeign] !== $chain
|
|
) {
|
|
$errorsChain[$this->chainedForeign] =
|
|
["error", dgettext(
|
|
"domframework",
|
|
"Can not change the external key"
|
|
)];
|
|
}
|
|
if ($this->chainedForeign !== null) {
|
|
$values[$this->chainedForeign] = $chain;
|
|
}
|
|
$errors = $this->objectDB->verify($values);
|
|
if (count($errors) > 0 || count($errorsChain) > 0) {
|
|
$this->renderrest(
|
|
$extension,
|
|
array_merge($errors, $errorsChain),
|
|
400
|
|
);
|
|
}
|
|
try {
|
|
$this->objectDB->insert($values);
|
|
$this->renderrest($extension, "OK", 200);
|
|
} catch (\Exception $e) {
|
|
$this->renderrest($extension, $e->getMessage(), 400);
|
|
}
|
|
}
|
|
);
|
|
|
|
$route->put(
|
|
"rest/" . $this->url_prefix . "(\.{extension})?/{id}",
|
|
function ($extension, $id, $chain = null) {
|
|
if ($this->chained !== null) {
|
|
if (
|
|
$this->chained->editright($this->authREST["email"], $chain) !==
|
|
true
|
|
) {
|
|
if ($this->authREST["email"] === "anonymous") {
|
|
throw new \Exception(dgettext(
|
|
"domframework",
|
|
"Anonymous not allowed"
|
|
), 401);
|
|
}
|
|
throw new \Exception(
|
|
dgettext("domframework", "Access forbidden"),
|
|
403
|
|
);
|
|
}
|
|
$this->chained->connect();
|
|
// $chainedvalues are the information associated to the $chain
|
|
$chainedvalues = $this->chained->keyexists($chain);
|
|
if ($chainedvalues === false) {
|
|
throw new \Exception(dgettext(
|
|
"domframework",
|
|
"Object not found"
|
|
), 404);
|
|
}
|
|
}
|
|
if ($this->accessright($this->authREST["email"]) !== true) {
|
|
if ($this->authREST["email"] === "anonymous") {
|
|
throw new \Exception(dgettext(
|
|
"domframework",
|
|
"Anonymous not allowed"
|
|
), 401);
|
|
}
|
|
throw new \Exception(
|
|
dgettext("domframework", "Access forbidden"),
|
|
403
|
|
);
|
|
}
|
|
if ($this->editright($this->authREST["email"]) !== true) {
|
|
if ($this->authREST["email"] === "anonymous") {
|
|
throw new \Exception(dgettext(
|
|
"domframework",
|
|
"Anonymous not allowed"
|
|
), 401);
|
|
}
|
|
throw new \Exception(
|
|
dgettext("domframework", "Access forbidden"),
|
|
403
|
|
);
|
|
}
|
|
if ($this->readonly($this->authREST["email"]) === true) {
|
|
throw new \Exception(
|
|
dgettext("domframework", "Access forbidden"),
|
|
403
|
|
);
|
|
}
|
|
if (!isset($extension) || $extension === null || $extension === "") {
|
|
$extension = reset($this->extensionsAllowed);
|
|
}
|
|
if (!in_array($extension, $this->extensionsAllowed, true)) {
|
|
throw new \Exception(dgettext(
|
|
"domframework",
|
|
"Extension not allowed"
|
|
), 403);
|
|
}
|
|
$this->connect();
|
|
parse_str(file_get_contents("php://input"), $values);
|
|
$errorsChain = [];
|
|
if (
|
|
$this->chainedForeign !== null &&
|
|
isset($values[$this->chainedForeign]) &&
|
|
$values[$this->chainedForeign] !== $chain
|
|
) {
|
|
$errorsChain[$this->chainedForeign] =
|
|
["error", dgettext(
|
|
"domframework",
|
|
"Can not change the external key"
|
|
)];
|
|
}
|
|
$errors = $this->objectDB->verify($values, $id);
|
|
if (count($errors) > 0 || count($errorsChain) > 0) {
|
|
$this->renderrest(
|
|
$extension,
|
|
array_merge($errors, $errorsChain),
|
|
400
|
|
);
|
|
}
|
|
try {
|
|
$this->objectDB->update($id, $values);
|
|
$this->renderrest($extension, "OK", 200);
|
|
} catch (\Exception $e) {
|
|
$this->renderrest($extension, $e->getMessage(), 400);
|
|
}
|
|
}
|
|
);
|
|
|
|
$route->delete(
|
|
"rest/" . $this->url_prefix . "(\.{extension})?/{id}",
|
|
function ($extension, $id, $chain = null) {
|
|
if ($this->chained !== null) {
|
|
if (
|
|
$this->chained->editright($this->authREST["email"], $chain) !==
|
|
true
|
|
) {
|
|
if ($this->authHTML["email"] === "anonymous") {
|
|
throw new \Exception(dgettext(
|
|
"domframework",
|
|
"Anonymous not allowed"
|
|
), 401);
|
|
}
|
|
throw new \Exception(
|
|
dgettext("domframework", "Access forbidden"),
|
|
403
|
|
);
|
|
}
|
|
$this->chained->connect();
|
|
// $chainedValues are the information associated to the $chain
|
|
$chainedValues = $this->chained->keyexists($chain);
|
|
if ($chainedValues === false) {
|
|
throw new \Exception(dgettext(
|
|
"domframework",
|
|
"Object not found"
|
|
), 404);
|
|
}
|
|
}
|
|
if ($this->accessright($this->authREST["email"]) !== true) {
|
|
if ($this->authREST["email"] === "anonymous") {
|
|
throw new \Exception(dgettext(
|
|
"domframework",
|
|
"Anonymous not allowed"
|
|
), 401);
|
|
}
|
|
throw new \Exception(
|
|
dgettext("domframework", "Access forbidden"),
|
|
403
|
|
);
|
|
}
|
|
if ($this->editright($this->authREST["email"]) !== true) {
|
|
if ($this->authREST["email"] === "anonymous") {
|
|
throw new \Exception(dgettext(
|
|
"domframework",
|
|
"Anonymous not allowed"
|
|
), 401);
|
|
}
|
|
throw new \Exception(
|
|
dgettext("domframework", "Access forbidden"),
|
|
403
|
|
);
|
|
}
|
|
if ($this->readonly($this->authREST["email"]) === true) {
|
|
throw new \Exception(
|
|
dgettext("domframework", "Access forbidden"),
|
|
403
|
|
);
|
|
}
|
|
if (!isset($extension) || $extension === null || $extension === "") {
|
|
$extension = reset($this->extensionsAllowed);
|
|
}
|
|
if (!in_array($extension, $this->extensionsAllowed, true)) {
|
|
throw new \Exception(dgettext(
|
|
"domframework",
|
|
"Extension not allowed"
|
|
), 403);
|
|
}
|
|
$this->connect();
|
|
try {
|
|
$this->objectDB->delete($id);
|
|
$this->renderrest($extension, "OK", 200);
|
|
} catch (\Exception $e) {
|
|
$this->renderrest($extension, $e->getMessage(), 400);
|
|
}
|
|
}
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Create the routes for HTML pages and the associated actions
|
|
*/
|
|
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(dgettext(
|
|
"domframework",
|
|
"Chained can not have an already chained object"
|
|
), 500);
|
|
}
|
|
$this->url_prefix = $this->chained->url_prefix . "/{chain}/" .
|
|
$this->url_prefix;
|
|
}
|
|
/**
|
|
* Add HTML routes
|
|
*/
|
|
$route = new Route();
|
|
$route->debug = $this->debug;
|
|
;
|
|
$route->allowSlashes = false;
|
|
$route->get($this->url_prefix . "/", function ($chain = null) use ($route) {
|
|
$route->redirect(
|
|
"/" . str_replace("{chain}", $chain, $this->url_prefix),
|
|
""
|
|
);
|
|
});
|
|
|
|
$route->get(
|
|
$this->url_prefix .
|
|
"(\?({p1}=({v1})?)(&{p2}=({v2})?(&{p3}=({v3})?)?)?)?",
|
|
function ($p1, $v1, $p2, $v2, $p3, $v3, $chain = null) use ($route) {
|
|
// List all the objects of the table
|
|
if ($this->chained !== null) {
|
|
if (
|
|
$this->chained->accessright($this->authHTML["email"], $chain) !==
|
|
true
|
|
) {
|
|
if ($this->authHTML["email"] === "anonymous") {
|
|
throw new \Exception(dgettext(
|
|
"domframework",
|
|
"Anonymous not allowed"
|
|
), 401);
|
|
}
|
|
throw new \Exception(dgettext(
|
|
"domframework",
|
|
"Access forbidden"
|
|
), 403);
|
|
}
|
|
$this->chained->connect();
|
|
// $chainedValues are the information associated to the $chain
|
|
$chainedValues = $this->chained->keyexists($chain);
|
|
if ($chainedValues === false) {
|
|
throw new \Exception(dgettext(
|
|
"domframework",
|
|
"Object not found"
|
|
), 404);
|
|
}
|
|
}
|
|
if ($this->accessright($this->authHTML["email"]) !== true) {
|
|
if ($this->authHTML["email"] === "anonymous") {
|
|
throw new \Exception(dgettext(
|
|
"domframework",
|
|
"Anonymous not allowed"
|
|
), 401);
|
|
}
|
|
throw new \Exception(dgettext(
|
|
"domframework",
|
|
"Access forbidden"
|
|
), 403);
|
|
}
|
|
|
|
if (
|
|
$this->chained !== null &&
|
|
$this->chained->editright($this->authHTML["email"], $chain) !== true
|
|
) {
|
|
$this->readwriteAllowed = false;
|
|
}
|
|
|
|
$this->url_prefix = str_replace("{chain}", $chain, $this->url_prefix);
|
|
$cookiePrefix = rawurlencode($this->url_prefix);
|
|
if (isset($_COOKIE["$cookiePrefix-num"])) {
|
|
$num = $_COOKIE["$cookiePrefix-num"];
|
|
}
|
|
if (isset($_COOKIE["$cookiePrefix-page"])) {
|
|
$page = $_COOKIE["$cookiePrefix-page"];
|
|
}
|
|
if (isset($_COOKIE["$cookiePrefix-search"])) {
|
|
$search = $_COOKIE["$cookiePrefix-search"];
|
|
}
|
|
// 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 ($p3 === "num") {
|
|
$num = $v3;
|
|
}
|
|
if ($p1 === "page") {
|
|
$page = $v1;
|
|
}
|
|
if ($p2 === "page") {
|
|
$page = $v2;
|
|
}
|
|
if ($p3 === "page") {
|
|
$page = $v3;
|
|
}
|
|
if ($p1 === "search") {
|
|
$search = $v1;
|
|
}
|
|
if ($p2 === "search") {
|
|
$search = $v2;
|
|
}
|
|
if ($p3 === "search") {
|
|
$search = $v3;
|
|
}
|
|
if (!isset($num) || $num === null || $num === "") {
|
|
$num = 10;
|
|
}
|
|
if (!isset($page) || $page === null || $page === "") {
|
|
$page = 1;
|
|
}
|
|
if (!isset($search) || $search === null || $search === "") {
|
|
$search = "";
|
|
}
|
|
$page = intval($page);
|
|
$num = intval($num);
|
|
$search = rawurldecode($search);
|
|
setcookie("$cookiePrefix-page", $page, time() + 3600 * 24 * 30, $this->path);
|
|
setcookie("$cookiePrefix-num", $num, time() + 3600 * 24 * 30, $this->path);
|
|
setcookie(
|
|
"$cookiePrefix-search",
|
|
$search,
|
|
time() + 3600 * 24 * 30,
|
|
$this->path
|
|
);
|
|
//echo "PAGE=$page\n";
|
|
//echo "NUM=$num\n";
|
|
//echo "SEARCH=$search\n";
|
|
//$route->debug=$this->debug;
|
|
$this->connect();
|
|
$csrf = new Csrf();
|
|
$token = $csrf->createToken();
|
|
$titles = $this->objectDB->titles();
|
|
unset($titles[$this->chainedForeign]);
|
|
$foreignSelect = null;
|
|
if ($this->chained !== null) {
|
|
$foreignSelect = [[$this->chainedForeign, $chain]];
|
|
}
|
|
if ($search === "") {
|
|
$data = $this->objectDB->read(
|
|
null,
|
|
array_keys($titles),
|
|
null,
|
|
null,
|
|
$foreignSelect
|
|
);
|
|
} else {
|
|
$criteria = [];
|
|
foreach (array_keys($titles) as $column) {
|
|
$s = $search;
|
|
if ($search[0] === "^") {
|
|
$s = substr($s, 1);
|
|
} else {
|
|
$s = "%$s";
|
|
}
|
|
if (substr($search, -1) === "$") {
|
|
$s = substr($s, 0, -1);
|
|
} else {
|
|
$s = "$s%";
|
|
}
|
|
$criteria[] = [$column, "$s", "LIKE"];
|
|
}
|
|
$data = $this->objectDB->read(
|
|
$criteria,
|
|
array_keys($titles),
|
|
null,
|
|
true,
|
|
$foreignSelect
|
|
);
|
|
}
|
|
// Limiting access to data only to data with read access right
|
|
foreach ($data as $key => $vals) {
|
|
if (
|
|
$this->accessright(
|
|
$this->authHTML["email"],
|
|
$vals[$this->objectDB->primary]
|
|
) !== true
|
|
) {
|
|
unset($data[$key]);
|
|
}
|
|
}
|
|
|
|
// Get the non mandatory foreign keys and display them instead of the
|
|
// unusable id
|
|
$foreignData = [];
|
|
if (isset($this->objectDB->foreign)) {
|
|
foreach ($this->objectDB->foreign as $foreign => $params) {
|
|
if (! isset($params[0])) {
|
|
throw new \Exception("Undefined foreign key", 500);
|
|
}
|
|
if (! isset($params[1])) {
|
|
throw new \Exception("Undefined foreign key column", 500);
|
|
}
|
|
$class = $params[0];
|
|
$column = $params[1];
|
|
require_once("models/model_$class.php");
|
|
$foreignObject = new $class(
|
|
$this->dsn,
|
|
$this->username,
|
|
$this->password,
|
|
$this->driver_options
|
|
);
|
|
if (isset($foreignObject->unique)) {
|
|
$tmpData = $foreignObject->read(null, array_merge(
|
|
[$column],
|
|
$foreignObject->unique
|
|
));
|
|
$associated = [];
|
|
$unique = reset($foreignObject->unique);
|
|
foreach ($tmpData as $vals) {
|
|
// TODO : If $foreignObject->unique is not an array ?
|
|
// or multidimensionnal array
|
|
$associated[$vals[$column]] = $vals[$unique];
|
|
}
|
|
// Add the unique text to the identifier
|
|
foreach ($data as $line => $vals) {
|
|
foreach ($vals as $col => $val) {
|
|
if ($col === $foreign && isset($associated[$val])) {
|
|
$data[$line][$col] = $associated[$val];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
$nbentries = count($data);
|
|
if ($num > 1000) {
|
|
$route->redirect("/" . str_replace("{chain}", $chain, $this->url_prefix)
|
|
. "?page=$page&num=1000&search=$search", "");
|
|
}
|
|
if ($page < 1) {
|
|
$route->redirect("/" . str_replace("{chain}", $chain, $this->url_prefix)
|
|
. "?page=1&num=$num&search=$search", "");
|
|
}
|
|
// Push on the last page if the values are too high
|
|
if ($nbentries > 0 && ($page - 1) * $num > $nbentries) {
|
|
$maxPage = intval($nbentries / $num) + 1;
|
|
$route->redirect("/" . str_replace("{chain}", $chain, $this->url_prefix) .
|
|
"?page=$maxPage&num=$num&search=$search", "");
|
|
}
|
|
|
|
|
|
$content = "";
|
|
// Internal CSS
|
|
if ($this->enableInternalCSS === true) {
|
|
$content .= "<style type='text/css' scoped='scoped'>\n";
|
|
$content .= ".routeSQL {
|
|
width:95%;
|
|
margin-left:auto;
|
|
margin-right:auto;
|
|
}\n";
|
|
$content .= ".routeSQL a {
|
|
text-decoration:none;
|
|
}\n";
|
|
$content .= ".routeSQL .topBar {
|
|
display: block;
|
|
overflow: auto;
|
|
}\n";
|
|
$content .= ".routeSQL .topBar .topleft {
|
|
display: inline;
|
|
float:left;
|
|
}\n";
|
|
$content .= ".routeSQL .topBar .topright {
|
|
display: inline;
|
|
float:right;
|
|
}\n";
|
|
$content .= ".routeSQL .bottomBar {
|
|
display: block;
|
|
overflow: auto;
|
|
}\n";
|
|
$content .= ".routeSQL .bottomBar .bottomleft {
|
|
display: inline;
|
|
float:left;
|
|
}\n";
|
|
$content .= ".routeSQL .bottomBar .bottomright {
|
|
display: inline;
|
|
float:right;
|
|
}\n";
|
|
$content .= ".routeSQL .actionExtern {
|
|
border:1px solid #ddd;
|
|
border-radius:5px;
|
|
padding:0px;
|
|
margin:3px;
|
|
float:left;
|
|
}\n";
|
|
$content .= ".routeSQL .actionExtern a {
|
|
display: block;
|
|
padding : 9px;
|
|
}\n";
|
|
$content .= ".routeSQL .numberEntryByDisplayArea {
|
|
border:1px solid #ddd;
|
|
border-radius:5px;
|
|
padding:10px;
|
|
margin:3px;
|
|
float:left;
|
|
}\n";
|
|
$content .= ".routeSQL .searchArea {
|
|
border:1px solid #ddd;
|
|
border-radius:5px;
|
|
padding:10px;
|
|
margin:3px;
|
|
float:left;
|
|
}\n";
|
|
$content .= ".routeSQL .searchArea form {
|
|
margin:-1px;
|
|
}\n";
|
|
$content .= ".routeSQL .numberEntryByDisplayArea form {
|
|
margin:-3px;
|
|
}\n";
|
|
$content .= ".routeSQL .informationArea {
|
|
border:1px solid #ddd;
|
|
border-radius:5px;
|
|
padding:10px;
|
|
margin:3px;
|
|
float:left;
|
|
}\n";
|
|
$content .= ".routeSQL div.paginatorArea {
|
|
float:left;
|
|
}\n";
|
|
$content .= ".routeSQL div.paginatorArea>ul>li>a {
|
|
display: block;
|
|
}\n";
|
|
$content .= ".routeSQL ul.paginatorArea {
|
|
list-style-type:none;
|
|
margin: 0px;
|
|
padding:0px;
|
|
border:1px solid #ddd;
|
|
border-radius:5px;
|
|
}\n";
|
|
$content .= ".routeSQL ul.paginatorArea li.selected {
|
|
background-color: #04d;
|
|
padding:0px;
|
|
}\n";
|
|
$content .= ".routeSQL ul.paginatorArea li.selected:first-child {
|
|
border-top-left-radius: 5px;
|
|
border-bottom-left-radius: 5px;
|
|
}\n";
|
|
$content .= ".routeSQL ul.paginatorArea li.selected:last-child {
|
|
border-top-right-radius: 5px;
|
|
border-bottom-right-radius: 5px;
|
|
}\n";
|
|
$content .= ".routeSQL ul.paginatorArea li.selected a {
|
|
padding : 10px;
|
|
color:white;
|
|
font-weight:bold;
|
|
}\n";
|
|
$content .= ".routeSQL ul.paginatorArea li a {
|
|
padding : 10px
|
|
}\n";
|
|
$content .= ".routeSQL ul.paginatorArea li {
|
|
display: inline-block;
|
|
}\n";
|
|
$content .= ".routeSQL table {
|
|
width:100%;
|
|
overflow:auto;
|
|
border-collapse:collapse;
|
|
}\n";
|
|
$content .= ".routeSQL table tr {
|
|
border-top:1px solid #ccc;
|
|
}\n";
|
|
$content .= ".routeSQL table th {
|
|
border-bottom:3px solid #ccc;
|
|
border-top:1px solid #fff;
|
|
padding:9px 5px 9px 1px;
|
|
}\n";
|
|
$content .= ".routeSQL table td {
|
|
empty-cells:true;
|
|
padding:9px 5px 9px 1px;
|
|
}\n";
|
|
$content .= ".routeSQL table .noentry {
|
|
text-align:center;
|
|
color:#c00;
|
|
font-weight:bolder;
|
|
}\n";
|
|
$content .= ".routeSQL table .action {
|
|
text-align:left;
|
|
padding-left: 8px;
|
|
}\n";
|
|
$content .= ".routeSQL table .action .edit {
|
|
color:#222;
|
|
font-weight:bolder;
|
|
}\n";
|
|
$content .= ".routeSQL table .action .delete {
|
|
color:#c00;
|
|
font-weight:bolder;
|
|
}\n";
|
|
$content .= ".routeSQL table .odd {
|
|
background-color:#f9f9f9;
|
|
}\n";
|
|
$content .= ".routeSQL .alert {
|
|
border-radius: 4px ;
|
|
border-width: 1px;
|
|
padding:10px;
|
|
}\n";
|
|
$content .= ".routeSQL .alert-success {
|
|
border-color: #d6e9c6;
|
|
background-color: #dff0d8;
|
|
color: #3c763d
|
|
}\n";
|
|
$content .= ".routeSQL .alert-info {
|
|
border-color: #bce8f1;
|
|
background-color: #d9edf7;
|
|
color: #31708f;
|
|
}\n";
|
|
$content .= ".routeSQL .alert-warning {
|
|
border-color: #faebcc;
|
|
background-color: #fcf8e3;
|
|
color: #8a6d3b;
|
|
}\n";
|
|
$content .= ".routeSQL .alert-danger {
|
|
border-color: #ebccd1;
|
|
background-color: #f2dede;
|
|
color: #a94442;
|
|
}\n";
|
|
$content .= "</style>\n";
|
|
}
|
|
$content .= "<div class='routeSQL'>\n";
|
|
$content .= $this->showflash();
|
|
$content .= " <div class='topBar'>\n";
|
|
$content .= " <div class='topleft'>\n";
|
|
foreach ($this->topBarLeft as $area) {
|
|
$areaName = $area . "Area";
|
|
$content .= $this->$areaName($nbentries, $page, $num, $search);
|
|
}
|
|
$content .= " </div>\n";
|
|
$content .= " <div class='topright'>\n";
|
|
foreach ($this->topBarRight as $area) {
|
|
$areaName = $area . "Area";
|
|
$content .= $this->$areaName($nbentries, $page, $num, $search);
|
|
}
|
|
$content .= " </div>\n";
|
|
$content .= " </div>\n"; // End of topBar
|
|
$content .= " <table>\n";
|
|
$content .= " <thead>\n";
|
|
$content .= " <tr>\n";
|
|
if (
|
|
$this->readwriteAllowed && $this->displayActions &&
|
|
$this->actionsAtEnd === false
|
|
) {
|
|
$content .= " <th>" . dgettext("domframework", "Actions") .
|
|
"</th>\n";
|
|
}
|
|
foreach ($titles as $title) {
|
|
$content .= " <th>" . htmlentities($title) . "</th>\n";
|
|
}
|
|
if (
|
|
$this->readwriteAllowed && $this->displayActions &&
|
|
$this->actionsAtEnd !== false
|
|
) {
|
|
$content .= " <th>" . dgettext("domframework", "Actions") .
|
|
"</th>\n";
|
|
}
|
|
$content .= " </tr>\n";
|
|
$content .= " </thead>\n";
|
|
$content .= " <tbody>\n";
|
|
if ($nbentries === 0) {
|
|
// Add one column more for actions
|
|
$countTitles = count($titles);
|
|
if ($this->readwriteAllowed && $this->displayActions) {
|
|
$countTitles++;
|
|
}
|
|
$content .= " <tr><td colspan='$countTitles' class='noentry'>";
|
|
$content .= dgettext("domframework", "No entry available");
|
|
$content .= "</td></tr>\n";
|
|
} else {
|
|
$i = 1;
|
|
$odd = "odd";
|
|
foreach ($data as $line) {
|
|
if ($i <= (($page - 1) * $num) || $i > (($page - 1) * $num + $num)) {
|
|
$i++;
|
|
continue;
|
|
}
|
|
$content .= " <tr class='$odd'>";
|
|
if ($odd === "odd") {
|
|
$odd = "even";
|
|
} else {
|
|
$odd = "odd";
|
|
}
|
|
if ($this->actionsAtEnd !== false) {
|
|
foreach ($line as $col) {
|
|
$content .= "<td>" . htmlentities($col) . "</td>";
|
|
}
|
|
}
|
|
if ($this->readwriteAllowed && $this->displayActions) {
|
|
$content .= "<td class='action'>";
|
|
$content .= " <a href='" . $route->baseURL() . $this->url_prefix . "/" .
|
|
$line[$this->objectDB->primary] . "' class='edit'>" .
|
|
$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 .= " class='delete'>" . $this->textDelete . "</a>";
|
|
foreach ($this->internalLinks as $linkData) {
|
|
if (! isset($linkData["linkname"])) {
|
|
throw new \Exception("No linkname defined !", 500);
|
|
}
|
|
$content .= " <a href='" . $route->baseURL() . $this->url_prefix . "/" .
|
|
$line[$this->objectDB->primary] . "/" .
|
|
$linkData["linkname"] . "'>";
|
|
if (isset($linkData["icon"])) {
|
|
$content .= $linkData["icon"];
|
|
} else {
|
|
$content .= $linkData["linkname"];
|
|
}
|
|
$content .= "</a>";
|
|
}
|
|
$content .= "</td>";
|
|
}
|
|
if ($this->actionsAtEnd === false) {
|
|
foreach ($line as $col) {
|
|
$content .= "<td>" . htmlentities($col) . "</td>";
|
|
}
|
|
}
|
|
$content .= "</tr>\n";
|
|
$i++;
|
|
}
|
|
}
|
|
$content .= " </tbody>\n";
|
|
$content .= " </table>\n";
|
|
$content .= " <div class='bottomBar'>\n";
|
|
$content .= " <div class='bottomleft'>\n";
|
|
foreach ($this->bottomBarLeft as $area) {
|
|
$areaName = $area . "Area";
|
|
$content .= $this->$areaName($nbentries, $page, $num, $search);
|
|
}
|
|
$content .= " </div>\n";
|
|
$content .= " <div class='bottomright'>\n";
|
|
foreach ($this->bottomBarRight as $area) {
|
|
$areaName = $area . "Area";
|
|
$content .= $this->$areaName($nbentries, $page, $num, $search);
|
|
}
|
|
$content .= " </div>\n";
|
|
$content .= " </div>\n"; // End of bottomBar
|
|
$content .= "</div>\n";
|
|
$this->rendererhtml($content);
|
|
}
|
|
);
|
|
|
|
$route->get(
|
|
$this->url_prefix . "/{id}/delete/{token}",
|
|
function ($id, $token, $chain = null) {
|
|
// Delete an existing object if the token is valid
|
|
if ($this->chained !== null) {
|
|
if (
|
|
$this->chained->editright($this->authHTML["email"], $chain) !==
|
|
true
|
|
) {
|
|
if ($this->authHTML["email"] === "anonymous") {
|
|
throw new \Exception(dgettext(
|
|
"domframework",
|
|
"Anonymous not allowed"
|
|
), 401);
|
|
}
|
|
throw new \Exception(
|
|
dgettext("domframework", "Access forbidden"),
|
|
403
|
|
);
|
|
}
|
|
$this->chained->connect();
|
|
// $chainedValues are the information associated to the $chain
|
|
$chainedValues = $this->chained->keyexists($chain);
|
|
if ($chainedValues === false) {
|
|
throw new \Exception(dgettext(
|
|
"domframework",
|
|
"Object not found"
|
|
), 404);
|
|
}
|
|
}
|
|
if ($this->accessright($this->authHTML["email"], $id) !== true) {
|
|
if ($this->authHTML["email"] === "anonymous") {
|
|
throw new \Exception(dgettext(
|
|
"domframework",
|
|
"Anonymous not allowed"
|
|
), 401);
|
|
}
|
|
throw new \Exception(
|
|
dgettext("domframework", "Access forbidden"),
|
|
403
|
|
);
|
|
}
|
|
if ($this->editright($this->authHTML["email"], $id) !== true) {
|
|
if ($this->authHTML["email"] === "anonymous") {
|
|
throw new \Exception(dgettext(
|
|
"domframework",
|
|
"Anonymous not allowed"
|
|
), 401);
|
|
}
|
|
throw new \Exception(
|
|
dgettext("domframework", "Access forbidden"),
|
|
403
|
|
);
|
|
}
|
|
if ($this->readonly($this->authHTML["email"], $id) === true) {
|
|
throw new \Exception(
|
|
dgettext("domframework", "Access forbidden"),
|
|
403
|
|
);
|
|
}
|
|
|
|
$this->connect();
|
|
$csrf = new Csrf();
|
|
$renderer = new Renderer();
|
|
$route = new Route();
|
|
try {
|
|
$csrf->checkToken($token);
|
|
$this->objectDB->delete($id);
|
|
$route->redirect(
|
|
"/" .
|
|
str_replace("{chain}", $chain, $this->url_prefix),
|
|
""
|
|
);
|
|
} catch (\Exception $e) {
|
|
$renderer->flash("ERROR", $e->getMessage());
|
|
$route->redirect(
|
|
"/" .
|
|
str_replace("{chain}", $chain, $this->url_prefix),
|
|
""
|
|
);
|
|
}
|
|
}
|
|
);
|
|
|
|
$route->get($this->url_prefix . "/add", function ($chain = null) {
|
|
// Add a new entry : form to be filled by the user
|
|
if ($this->chained !== null) {
|
|
if (
|
|
$this->chained->editright($this->authHTML["email"], $chain) !==
|
|
true
|
|
) {
|
|
if ($this->authHTML["email"] === "anonymous") {
|
|
throw new \Exception(dgettext(
|
|
"domframework",
|
|
"Anonymous not allowed"
|
|
), 401);
|
|
}
|
|
throw new \Exception(
|
|
dgettext("domframework", "Access forbidden"),
|
|
403
|
|
);
|
|
}
|
|
$this->chained->connect();
|
|
// $chainedValues are the information associated to the $chain
|
|
$chainedValues = $this->chained->keyexists($chain);
|
|
if ($chainedValues === false) {
|
|
throw new \Exception(dgettext(
|
|
"domframework",
|
|
"Object not found"
|
|
), 404);
|
|
}
|
|
}
|
|
if ($this->accessright($this->authHTML["email"]) !== true) {
|
|
if ($this->authHTML["email"] === "anonymous") {
|
|
throw new \Exception(dgettext(
|
|
"domframework",
|
|
"Anonymous not allowed"
|
|
), 401);
|
|
}
|
|
throw new \Exception(
|
|
dgettext("domframework", "Access forbidden"),
|
|
403
|
|
);
|
|
}
|
|
if ($this->editright($this->authHTML["email"]) !== true) {
|
|
if ($this->authHTML["email"] === "anonymous") {
|
|
throw new \Exception(dgettext(
|
|
"domframework",
|
|
"Anonymous not allowed"
|
|
), 401);
|
|
}
|
|
throw new \Exception(
|
|
dgettext("domframework", "Access forbidden"),
|
|
403
|
|
);
|
|
}
|
|
if ($this->readonly($this->authHTML["email"]) === true) {
|
|
throw new \Exception(
|
|
dgettext("domframework", "Access forbidden"),
|
|
403
|
|
);
|
|
}
|
|
|
|
$this->connect();
|
|
|
|
// Get the non mandatory foreign keys and display them instead of the
|
|
// unusable id
|
|
$foreignData = [];
|
|
if (isset($this->objectDB->foreign)) {
|
|
foreach ($this->objectDB->foreign as $foreign => $params) {
|
|
if (! isset($params[0])) {
|
|
throw new \Exception("Undefined foreign key", 500);
|
|
}
|
|
if (! isset($params[1])) {
|
|
throw new \Exception("Undefined foreign key column", 500);
|
|
}
|
|
$class = $params[0];
|
|
$column = $params[1];
|
|
require_once("models/model_$class.php");
|
|
$foreignObject = new $class(
|
|
$this->dsn,
|
|
$this->username,
|
|
$this->password,
|
|
$this->driver_options
|
|
);
|
|
if (isset($foreignObject->unique)) {
|
|
$tmpData = $foreignObject->read(null, array_merge(
|
|
[$column],
|
|
$foreignObject->unique
|
|
));
|
|
$associated = [];
|
|
$unique = reset($foreignObject->unique);
|
|
foreach ($tmpData as $vals) {
|
|
// TODO : If $foreignObject->unique is not an array ?
|
|
// or multidimensionnal array
|
|
$associated[$vals[$column]] = $vals[$unique];
|
|
}
|
|
$foreignData[$foreign] = $associated;
|
|
}
|
|
}
|
|
}
|
|
|
|
$content = $this->showflash();
|
|
$values = [];
|
|
$errors = [];
|
|
$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"]);
|
|
}
|
|
|
|
if ($this->enableInternalCSS === true) {
|
|
// CSS is in edit an id too !
|
|
$content .= "<style type='text/css' scoped='scoped'>\n";
|
|
$content .= "#form .col-sm-2 {
|
|
float:left;
|
|
width: 16.66666667%;
|
|
padding-left:15px;
|
|
padding-right:15px;
|
|
};\n";
|
|
$content .= "#form .col-sm-10 {
|
|
float:left;
|
|
width: 83.33333333%;
|
|
}\n";
|
|
$content .= "#form .col-sm-12 {
|
|
width: 100%;
|
|
}\n";
|
|
$content .= "#form input[type='submit'] {
|
|
width:93%;
|
|
margin-left:auto;
|
|
margin-right:auto
|
|
}\n";
|
|
$content .= "#form .btn-primary {
|
|
color: #fff;
|
|
background-color: #428bca;
|
|
border-color: #357ebd;
|
|
}\n";
|
|
$content .= ".help-block {
|
|
margin-left:16.7%;
|
|
display: block;
|
|
color:#a94442;
|
|
} \n";
|
|
$content .= "#form input[type='text'] {
|
|
background-color:#fff;
|
|
}\n";
|
|
$content .= "#form .has-error label {
|
|
color:#a94442;
|
|
}\n";
|
|
$content .= "#form .has-error .form-control {
|
|
border-color:#a94442;
|
|
box-shadow: 0px 1px 1px rgba(0, 0, 0, 0.075) inset;
|
|
}\n";
|
|
$content .= ".form-group {
|
|
margin-bottom: 15px;
|
|
}\n";
|
|
$content .= ".form-horizontal .control-label {
|
|
text-align: right;
|
|
}\n";
|
|
$content .= "label {
|
|
display: inline-block;
|
|
font-weight: 700;
|
|
}\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 .= "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 .= ".alert {
|
|
border-radius: 4px ;
|
|
border-width: 1px;
|
|
padding:10px;
|
|
}\n";
|
|
$content .= ".alert-success {
|
|
border-color: #d6e9c6;
|
|
background-color: #dff0d8;
|
|
color: #3c763d
|
|
}\n";
|
|
$content .= ".alert-info {
|
|
border-color: #bce8f1;
|
|
background-color: #d9edf7;
|
|
color: #31708f;
|
|
}\n";
|
|
$content .= ".alert-warning {
|
|
border-color: #faebcc;
|
|
background-color: #fcf8e3;
|
|
color: #8a6d3b;
|
|
}\n";
|
|
$content .= ".alert-danger {
|
|
border-color: #ebccd1;
|
|
background-color: #f2dede;
|
|
color: #a94442;
|
|
}\n";
|
|
$content .= "</style>\n";
|
|
// CSS is in edit an id too !
|
|
}
|
|
|
|
$f = new Form();
|
|
$fields = [];
|
|
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], true)) {
|
|
$field->mandatory = true;
|
|
}
|
|
if (in_array("autoincrement", $this->objectDB->fields[$key], true)) {
|
|
$field->type = "hidden";
|
|
}
|
|
if ($key === $this->chainedForeign) {
|
|
$field->defaults = $chain;
|
|
$field->readonly = true;
|
|
}
|
|
if (isset($foreignData[$key])) {
|
|
// Add a select list to the foreign keys : the user can't add a value
|
|
// that doesn't exists
|
|
$field->type = "select";
|
|
$field->defaults = $foreignData[$key];
|
|
}
|
|
$fields[] = $field;
|
|
unset($field);
|
|
}
|
|
|
|
$field = new Formfield("submit", dgettext(
|
|
"domframework",
|
|
"Save the data"
|
|
));
|
|
$field->defaults = dgettext("domframework", "Save the data");
|
|
$field->type = "submit";
|
|
$fields[] = $field;
|
|
unset($field);
|
|
$f->fields($fields);
|
|
$content .= $f->printHTML("post", $values, $errors);
|
|
$this->rendererhtml($content);
|
|
});
|
|
|
|
$route->post($this->url_prefix . "/add", function ($chain = null) use ($route) {
|
|
// Add a new entry : effective save of the data
|
|
if ($this->chained !== null) {
|
|
if (
|
|
$this->chained->editright($this->authHTML["email"], $chain) !==
|
|
true
|
|
) {
|
|
if ($this->authHTML["email"] === "anonymous") {
|
|
throw new \Exception(dgettext(
|
|
"domframework",
|
|
"Anonymous not allowed"
|
|
), 401);
|
|
}
|
|
throw new \Exception(
|
|
dgettext("domframework", "Access forbidden"),
|
|
403
|
|
);
|
|
}
|
|
$this->chained->connect();
|
|
// $chainedvalues are the information associated to the $chain
|
|
$chainedvalues = $this->chained->keyexists($chain);
|
|
if ($chainedvalues === false) {
|
|
throw new \Exception(dgettext(
|
|
"domframework",
|
|
"Object not found"
|
|
), 404);
|
|
}
|
|
}
|
|
if ($this->accessright($this->authHTML["email"]) !== true) {
|
|
if ($this->authHTML["email"] === "anonymous") {
|
|
throw new \Exception(dgettext(
|
|
"domframework",
|
|
"Anonymous not allowed"
|
|
), 401);
|
|
}
|
|
throw new \Exception(
|
|
dgettext("domframework", "Access forbidden"),
|
|
403
|
|
);
|
|
}
|
|
if ($this->editright($this->authHTML["email"]) !== true) {
|
|
if ($this->authHTML["email"] === "anonymous") {
|
|
throw new \Exception(dgettext(
|
|
"domframework",
|
|
"Anonymous not allowed"
|
|
), 401);
|
|
}
|
|
throw new \Exception(
|
|
dgettext("domframework", "Access forbidden"),
|
|
403
|
|
);
|
|
}
|
|
if ($this->readonly($this->authHTML["email"]) === true) {
|
|
throw new \Exception(
|
|
dgettext("domframework", "Access forbidden"),
|
|
403
|
|
);
|
|
}
|
|
|
|
$this->connect();
|
|
$f = new Form();
|
|
$values = $f->values();
|
|
$errorsChain = [];
|
|
if (
|
|
$this->chainedForeign !== null &&
|
|
isset($values[$this->chainedForeign]) &&
|
|
$values[$this->chainedForeign] !== $chain
|
|
) {
|
|
$errorsChain[$this->chainedForeign] =
|
|
["error", dgettext(
|
|
"domframework",
|
|
"Can not change the external key"
|
|
)];
|
|
}
|
|
$errors = $this->objectDB->verify($values);
|
|
if (count($errors) == 0 && count($errorsChain) == 0) {
|
|
try {
|
|
$this->objectDB->insert($values);
|
|
$renderer = new Renderer();
|
|
$renderer->flash("SUCCESS", dgettext(
|
|
"domframework",
|
|
"Creation done"
|
|
));
|
|
$route->redirect(
|
|
"/" .
|
|
str_replace("{chain}", $chain, $this->url_prefix),
|
|
""
|
|
);
|
|
} catch (\Exception $e) {
|
|
$renderer = new Renderer();
|
|
$renderer->flash("ERROR", $e->getMessage());
|
|
}
|
|
} else {
|
|
$renderer = new Renderer();
|
|
foreach ($errorsChain 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("/" . str_replace("{chain}", $chain, $this->url_prefix) .
|
|
"/add", "");
|
|
});
|
|
|
|
$route->get($this->url_prefix . "/{id}", function ($id, $chain = null) {
|
|
// List the details of one existing object
|
|
if ($this->chained !== null) {
|
|
if (
|
|
$this->chained->accessright($this->authHTML["email"], $chain) !==
|
|
true
|
|
) {
|
|
if ($this->authHTML["email"] === "anonymous") {
|
|
throw new \Exception(dgettext(
|
|
"domframework",
|
|
"Anonymous not allowed"
|
|
), 401);
|
|
}
|
|
throw new \Exception(
|
|
dgettext("domframework", "Access forbidden"),
|
|
403
|
|
);
|
|
}
|
|
$this->chained->connect();
|
|
// $chainedvalues are the information associated to the $chain
|
|
$chainedvalues = $this->chained->keyexists($chain);
|
|
if ($chainedvalues === false) {
|
|
throw new \Exception(dgettext(
|
|
"domframework",
|
|
"Object not found"
|
|
), 404);
|
|
}
|
|
}
|
|
if ($this->accessright($this->authHTML["email"], $id) !== true) {
|
|
if ($this->authHTML["email"] === "anonymous") {
|
|
throw new \Exception(dgettext(
|
|
"domframework",
|
|
"Anonymous not allowed"
|
|
), 401);
|
|
}
|
|
throw new \Exception(
|
|
dgettext("domframework", "Access forbidden"),
|
|
403
|
|
);
|
|
}
|
|
if (
|
|
$this->chained !== null &&
|
|
$this->chained->editright($this->authHTML["email"], $chain) !== true
|
|
) {
|
|
$this->readwriteAllowed = false;
|
|
}
|
|
if ($this->readwriteAllowed === true) {
|
|
$this->readwriteAllowed = $this->editright(
|
|
$this->authHTML["email"],
|
|
$id
|
|
);
|
|
}
|
|
$readonly = $this->readonly($this->authHTML["email"], $id);
|
|
|
|
$this->connect();
|
|
// Get the non mandatory foreign keys and display them instead of the
|
|
// unusable id
|
|
$foreignData = [];
|
|
if (isset($this->objectDB->foreign)) {
|
|
foreach ($this->objectDB->foreign as $foreign => $params) {
|
|
if (! isset($params[0])) {
|
|
throw new \Exception("Undefined foreign key", 500);
|
|
}
|
|
if (! isset($params[1])) {
|
|
throw new \Exception("Undefined foreign key column", 500);
|
|
}
|
|
$class = $params[0];
|
|
$column = $params[1];
|
|
require_once("models/model_$class.php");
|
|
$foreignObject = new $class(
|
|
$this->dsn,
|
|
$this->username,
|
|
$this->password,
|
|
$this->driver_options
|
|
);
|
|
if (isset($foreignObject->unique)) {
|
|
$tmpData = $foreignObject->read(null, array_merge(
|
|
[$column],
|
|
$foreignObject->unique
|
|
));
|
|
$associated = [];
|
|
$unique = reset($foreignObject->unique);
|
|
foreach ($tmpData as $vals) {
|
|
// TODO : If $foreignObject->unique is not an array ?
|
|
// or multidimensionnal array
|
|
$associated[$vals[$column]] = $vals[$unique];
|
|
}
|
|
$foreignData[$foreign] = $associated;
|
|
}
|
|
}
|
|
}
|
|
$content = $this->showflash();
|
|
$values = [];
|
|
$errors = [];
|
|
$titles = $this->objectDB->titles();
|
|
$values = $this->objectDB->read([[$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"]);
|
|
}
|
|
|
|
if ($this->enableInternalCSS === true) {
|
|
// CSS is in add too !
|
|
$content .= "<style type='text/css' scoped='scoped'>\n";
|
|
$content .= "#form .col-sm-2 {
|
|
float:left;
|
|
width: 16.66666667%;
|
|
padding-left:15px;
|
|
padding-right:15px;
|
|
};\n";
|
|
$content .= "#form .col-sm-10 {
|
|
float:left;
|
|
width: 83.33333333%;
|
|
}\n";
|
|
$content .= "#form .col-sm-12 {
|
|
width: 100%;
|
|
}\n";
|
|
$content .= "#form input[type='submit'] {
|
|
width:93%;
|
|
margin-left:auto;
|
|
margin-right:auto
|
|
}\n";
|
|
$content .= "#form .btn-primary {
|
|
color: #fff;
|
|
background-color: #428bca;
|
|
border-color: #357ebd;
|
|
}\n";
|
|
$content .= ".help-block {
|
|
margin-left:16.7%;
|
|
display: block;
|
|
color:#a94442;
|
|
} \n";
|
|
$content .= "#form input[type='text'] {
|
|
background-color:#fff;
|
|
}\n";
|
|
$content .= "#form .has-error label {
|
|
color:#a94442;
|
|
}\n";
|
|
$content .= "#form .has-error .form-control {
|
|
border-color:#a94442;
|
|
box-shadow: 0px 1px 1px rgba(0, 0, 0, 0.075) inset;
|
|
}\n";
|
|
$content .= ".form-group {
|
|
margin-bottom: 15px;
|
|
}\n";
|
|
$content .= ".form-horizontal .control-label {
|
|
text-align: right;
|
|
}\n";
|
|
$content .= "label {
|
|
display: inline-block;
|
|
font-weight: 700;
|
|
}\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 .= "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 .= ".alert {
|
|
border-radius: 4px ;
|
|
border-width: 1px;
|
|
padding:10px;
|
|
}\n";
|
|
$content .= ".alert-success {
|
|
border-color: #d6e9c6;
|
|
background-color: #dff0d8;
|
|
color: #3c763d
|
|
}\n";
|
|
$content .= ".alert-info {
|
|
border-color: #bce8f1;
|
|
background-color: #d9edf7;
|
|
color: #31708f;
|
|
}\n";
|
|
$content .= ".alert-warning {
|
|
border-color: #faebcc;
|
|
background-color: #fcf8e3;
|
|
color: #8a6d3b;
|
|
}\n";
|
|
$content .= ".alert-danger {
|
|
border-color: #ebccd1;
|
|
background-color: #f2dede;
|
|
color: #a94442;
|
|
}\n";
|
|
$content .= "</style>\n";
|
|
// CSS is in add too !
|
|
}
|
|
|
|
$f = new Form();
|
|
$fields = [];
|
|
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], true)) {
|
|
$field->mandatory = true;
|
|
}
|
|
if (in_array("autoincrement", $this->objectDB->fields[$key], true)) {
|
|
$field->type = "hidden";
|
|
}
|
|
if ($readonly === true || $this->readwriteAllowed === false) {
|
|
$field->readonly = true;
|
|
}
|
|
if ($key === $this->chainedForeign) {
|
|
$field->defaults = $chain;
|
|
$field->readonly = true;
|
|
}
|
|
if (isset($foreignData[$key])) {
|
|
// Add a select list to the foreign keys : the user can't add a value
|
|
// that doesn't exists
|
|
$field->type = "select";
|
|
$field->defaults = $foreignData[$key];
|
|
}
|
|
$fields[] = $field;
|
|
unset($field);
|
|
}
|
|
|
|
if ($readonly === false && $this->readwriteAllowed === true) {
|
|
$field = new Formfield("submit", dgettext(
|
|
"domframework",
|
|
"Save the data"
|
|
));
|
|
$field->defaults = dgettext("domframework", "Save the data");
|
|
$field->type = "submit";
|
|
$fields[] = $field;
|
|
unset($field);
|
|
}
|
|
$f->fields($fields);
|
|
$content .= $f->printHTML("post", $values, $errors);
|
|
$this->rendererhtml($content);
|
|
});
|
|
|
|
$route->post($this->url_prefix . "/{id}", function ($id, $chain = null) use ($route) {
|
|
// Save the details of one existing object
|
|
if ($this->chained !== null) {
|
|
if (
|
|
$this->chained->editright($this->authHTML["email"], $chain) !==
|
|
true
|
|
) {
|
|
if ($this->authHTML["email"] === "anonymous") {
|
|
throw new \Exception(dgettext(
|
|
"domframework",
|
|
"Anonymous not allowed"
|
|
), 401);
|
|
}
|
|
throw new \Exception(
|
|
dgettext("domframework", "Access forbidden"),
|
|
403
|
|
);
|
|
}
|
|
$this->chained->connect();
|
|
// $chainedvalues are the information associated to the $chain
|
|
$chainedvalues = $this->chained->keyexists($chain);
|
|
if ($chainedvalues === false) {
|
|
throw new \Exception(dgettext(
|
|
"domframework",
|
|
"Object not found"
|
|
), 404);
|
|
}
|
|
}
|
|
if ($this->accessright($this->authHTML["email"], $id) !== true) {
|
|
if ($this->authHTML["email"] === "anonymous") {
|
|
throw new \Exception(dgettext(
|
|
"domframework",
|
|
"Anonymous not allowed"
|
|
), 401);
|
|
}
|
|
throw new \Exception(
|
|
dgettext("domframework", "Access forbidden"),
|
|
403
|
|
);
|
|
}
|
|
if ($this->editright($this->authHTML["email"], $id) !== true) {
|
|
if ($this->authHTML["email"] === "anonymous") {
|
|
throw new \Exception(dgettext(
|
|
"domframework",
|
|
"Anonymous not allowed"
|
|
), 401);
|
|
}
|
|
throw new \Exception(
|
|
dgettext("domframework", "Access forbidden"),
|
|
403
|
|
);
|
|
}
|
|
if ($this->readonly($this->authHTML["email"], $id) === true) {
|
|
throw new \Exception(
|
|
dgettext("domframework", "Access forbidden"),
|
|
403
|
|
);
|
|
}
|
|
|
|
$this->connect();
|
|
$oldvalues = $this->objectDB->read([[$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);
|
|
}
|
|
$errorsChain = [];
|
|
if (
|
|
$this->chainedForeign !== null &&
|
|
isset($values[$this->chainedForeign]) &&
|
|
$values[$this->chainedForeign] !== $chain
|
|
) {
|
|
$errorsChain[$this->chainedForeign] =
|
|
["error", dgettext(
|
|
"domframework",
|
|
"Can not change the external key"
|
|
)];
|
|
}
|
|
if ($this->chainedForeign !== null) {
|
|
$values[$this->chainedForeign] = $chain;
|
|
}
|
|
$errors = $this->objectDB->verify($values, $id);
|
|
if (count($errors) == 0 && count($errorsChain) == 0) {
|
|
try {
|
|
$this->objectDB->update($id, $values);
|
|
$renderer = new Renderer();
|
|
$renderer->flash("SUCCESS", dgettext(
|
|
"domframework",
|
|
"Update done"
|
|
));
|
|
$route->redirect(
|
|
"/" .
|
|
str_replace("{chain}", $chain, $this->url_prefix),
|
|
""
|
|
);
|
|
} catch (\Exception $e) {
|
|
$renderer = new Renderer();
|
|
$renderer->flash("ERROR", $e->getMessage());
|
|
}
|
|
} else {
|
|
$renderer = new Renderer();
|
|
foreach ($errorsChain 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("/" . str_replace("{chain}", $chain, $this->url_prefix) .
|
|
"/$id", "");
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Authorization : Return TRUE if the user right allow to see the data
|
|
* Return FALSE else
|
|
* @param array $auth The auth to authenticate
|
|
* @param integer|null $id The id to examine
|
|
*/
|
|
public function accessright($auth, $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,
|
|
$auth,
|
|
"/" . $this->model_class . "/$id"
|
|
);
|
|
// echo "RESULT=$result\n";
|
|
if ($result === "RO") {
|
|
return true;
|
|
}
|
|
if ($result === "RW") {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Authorization : Return TRUE if the user right allow to edit the data
|
|
* Return FALSE else
|
|
* @param array $auth The auth to authenticate
|
|
* @param integer|null $id The id to examine
|
|
*/
|
|
public function editright($auth, $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,
|
|
$auth,
|
|
"/" . $this->model_class . "/$id"
|
|
);
|
|
// echo "RESULT=$result\n";
|
|
if ($result === "RW") {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Authorization : Return TRUE if the $id is in READONLY for the user or
|
|
* FALSE if the user have the RW rights
|
|
* @param array $auth The auth to authenticate
|
|
* @param integer|null $id The id to examine
|
|
*/
|
|
public function readonly($auth, $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,
|
|
$auth,
|
|
"/" . $this->model_class . "/$id"
|
|
);
|
|
// echo "RESULT=$result\n";
|
|
if ($result === "RO") {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Return the data of the row if the $id exists in the primary key of the
|
|
* table
|
|
* Return FALSE in the other cases
|
|
* @param integer $id The id to examine
|
|
*/
|
|
public function keyexists($id)
|
|
{
|
|
$data = $this->objectDB->read([[$this->objectDB->primary,
|
|
$id]]);
|
|
if (count($data) > 0) {
|
|
return $data[0];
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Display the data in HTML with the view class/method if they are defined
|
|
* @param array $data The data to display
|
|
*/
|
|
private function rendererhtml($data)
|
|
{
|
|
$route = new Route();
|
|
|
|
$html = new Outputhtml();
|
|
$replacement = ["{baseurl}" => $route->baseURL()];
|
|
if ($this->rendererHTMLlayout === false) {
|
|
$this->rendererHTMLlayout = "<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<title>{title}</title>
|
|
<meta http-equiv='Content-Type' content='text/html; charset=UTF-8'/>
|
|
</head>
|
|
<body>
|
|
{content}
|
|
</body>
|
|
</html>";
|
|
}
|
|
|
|
// TODO : Test the $this->rendererHTMLclass, $this->rendererHTMLmethod !
|
|
echo $html->out(
|
|
$data,
|
|
false,
|
|
$this->rendererHTMLclass,
|
|
$this->rendererHTMLmethod,
|
|
$this->rendererHTMLlayout,
|
|
$replacement
|
|
);
|
|
exit;
|
|
}
|
|
|
|
/**
|
|
* Return the result converted by JSON/XML, defined in REST
|
|
* @param string $extension The display method
|
|
* @param array $data The data to return
|
|
* @param integer $getCode The HTTP code to return (200 OK by default)
|
|
*/
|
|
private function renderrest($extension, $data, $getCode = 200)
|
|
{
|
|
$http = new Http();
|
|
@header($_SERVER["SERVER_PROTOCOL"] . " $getCode " .
|
|
$http->codetext($getCode));
|
|
$class = "Output$extension";
|
|
$result = new $class();
|
|
echo $result->out($data) . "\n";
|
|
exit;
|
|
}
|
|
}
|