Ubiquity  2.0.0
php rapid development framework
RestTrait.php
Go to the documentation of this file.
1 <?php
2 
4 
9 use Ajax\JsUtils;
21 
28 class RestTrait{
29 
30  abstract public function _getAdminFiles();
31 
32  abstract public function _getAdminViewer();
33 
43  abstract protected function showSimpleMessage($content, $type, $icon="info", $timeout=NULL, $staticName=null);
44 
45  public function initRestCache($refresh=true) {
46  $config=Startup::getConfig();
47  \ob_start();
48  CacheManager::initCache($config, "rest");
49  CacheManager::initCache($config, "controllers");
50  $message=\ob_get_clean();
51  echo $this->showSimpleMessage(\nl2br($message), "info", "info", 4000);
52  if ($refresh === true)
53  $this->_refreshRest(true);
54  echo $this->jquery->compile($this->view);
55  }
56 
57  protected function _refreshRest($refresh=false) {
58  $result="";
59  try {
60  $restRoutes=CacheManager::getRestRoutes();
61  if (\sizeof($restRoutes) > 0) {
62  $result=$this->_getAdminViewer()->getRestRoutesTab($restRoutes);
63  } else {
64  $result=$this->showSimpleMessage("No resource Rest found. You can add a new resource.", "", "warning circle", null, "tabsRest");
65  }
66  } catch ( UbiquityException $e ) {
67  $result.=$this->showSimpleMessage(\nl2br($e->getMessage()), "error", "warning circle", null, "tabsRest");
68  }
70  if ($refresh) {
71  echo $result;
72  }
73  }
74 
75  public function _displayRestFormTester() {
76  $path=@$_POST["path"];
77  $resource=@$_POST["resource"];
78  $controller=@$_POST["controller"];
79  $controller=\urldecode($controller);
80  $action=@$_POST["action"];
81  $msgHelp=$this->_displayActionDoc($controller, $action);
82  $frm=$this->jquery->semantic()->htmlForm("frmTester-" . $path);
83  $pathId=JString::cleanIdentifier($path);
84  $containerId="div-tester-" . $pathId;
85  $input=$frm->addInput("path", null, "text", $path);
86  $pathField=$input->getDataField()->setIdentifier("path-" . $path)->addClass("_path");
87  $dd=$input->addDropdown("GET", Constants::REQUEST_METHODS);
88  $methodField=$dd->setIdentifier("dd-method-" . $path)->getDataField()->setProperty("name", "method");
89  $methodField->setIdentifier("method-" . $path)->addClass("_method");
90  $input->addAction("Headers...", "right", "barcode")->addClass("basic _requestWithHeaders")->setTagName("div");
91  $input->addAction("Parameters...", "right", "settings")->addClass("basic _requestWithParams")->setTagName("div");
92  $btGo=$input->addAction("Send")->setColor("blue");
93  $btGo->addIcon("send");
94  $btGo->setIdentifier("btGo-" . $path);
95 
96  $frmHeaders=new HtmlForm("frm-headers-" . $path);
97  $frmParameters=new HtmlForm("frm-parameters-" . $path);
98 
99  $this->jquery->postOnClick("#" . $btGo->getIdentifier(), $this->_getAdminFiles()->getAdminBaseRoute() . "/_runRestMethod", "{pathId: '" . $path . "',path: $('#" . $pathField->getIdentifier() . "').val(),method: $('#" . $methodField->getIdentifier() . "').val(),headers:$('#" . $frmHeaders->getIdentifier() . "').serialize(),params:$('#" . $frmParameters->getIdentifier() . "').serialize()}", "#" . $containerId . " ._runRestMethod", [ ]);
100  $this->jquery->postOnClick("#" . $containerId . " ._requestWithParams", $this->_getAdminFiles()->getAdminBaseRoute() . "/_runPostWithParams/_/parameter/rest", "{actualParams:$('#" . $frmParameters->getIdentifier() . "').serialize(),model: '" . $resource . "',toUpdate:'" . $frmParameters->getIdentifier() . "',method:$('#" . $containerId . " ._method').val(),url:$('#" . $containerId . " ._path').val()}", "#modal", [ "attr" => "","hasLoader" => false ]);
101  $this->jquery->postOnClick("#" . $containerId . " ._requestWithHeaders", $this->_getAdminFiles()->getAdminBaseRoute() . "/_runPostWithParams/_/header/rest", "{actualParams: $('#" . $frmHeaders->getIdentifier() . "').serialize(),model: '" . $resource . "',toUpdate:'" . $frmHeaders->getIdentifier() . "',method:$('#" . $containerId . " ._method').val(),url:$('#" . $containerId . " ._path').val()}", "#modal", [ "attr" => "","hasLoader" => false ]);
102  if (!$msgHelp->_empty) {
103  $this->jquery->exec('$("#' . JString::cleanIdentifier("help-" . $action . $controller) . '").transition("show");', true);
104  }
105  $this->jquery->compile($this->view);
106  $this->loadView($this->_getAdminFiles()->getViewRestFormTester(), [ "frmHeaders" => $frmHeaders,"frmParameters" => $frmParameters,"frmTester" => $frm,"pathId" => $pathId,"msgHelp" => $msgHelp ]);
107  }
108 
109  protected function _displayActionDoc($controller, $action) {
110  $docParser=DocParser::docMethodParser($controller, $action);
111  $msg=$this->showSimpleMessage($docParser->getDescriptionAsHtml(), "", "help circle blue", null, "msg-help-" . $action . $controller);
112  $msg->addHeader("Method " . $action);
113  $msg->addList($docParser->getMethodParamsReturnAsHtml());
114  $msg->addClass("hidden transition");
115  $msg->_empty=$docParser->isEmpty();
116  return $msg;
117  }
118 
119  public function _frmNewResource() {
120  $config=Startup::getConfig();
121  $frm=$this->jquery->semantic()->htmlForm("frmNewResource");
122  $frm->addMessage("msg", "Creating a new REST controller...", "New resource", HtmlIconGroups::corner("heartbeat", "plus"));
123  $input=$frm->addInput("ctrlName", "Controller name")->addRule("empty");
124  $input->labeled(RestServer::getRestNamespace() . "\\");
125  $fields=$frm->addFields();
126  $resources=CacheManager::getModels($config, true);
127  $resources=\array_combine($resources, $resources);
128  $fields->addDropdown("resource", $resources, "Resource", end($resources))->addRule([ "exactCount[1]" ]);
129  $fields->addInput("route", "Main route path", "text", "/rest/")->addRule("empty");
130  $frm->addCheckbox("re-init", "Re-init Rest cache (recommanded)", "reInit")->setChecked(true);
131 
132  $frm->addDivider();
133  $fields=$frm->addFields();
134  $bt=$fields->addButton("bt-create-new-resource", "Create new controller", "teal");
135  $bt->addIcon("plus");
136  $fields->addButton("bt-cancel-new-resource", "Cancel", "", "$('#frmNewResource').hide();$('#divRest').show();");
137  $frm->setValidationParams([ "on" => "blur","inline" => false ]);
138  $frm->addErrorMessage();
139  $frm->setSubmitParams($this->_getAdminFiles()->getAdminBaseRoute() . "/_createNewResource", "#divRest", [ "dataType" => "html" ]);
140  $this->jquery->exec("$('#divRest').hide();$('#div-new-resource').show();", true);
141  echo $frm->compile($this->jquery, $this->view);
142  echo $this->jquery->compile($this->view);
143  }
144 
145  public function _createNewResource() {
146  if (URequest::isPost()) {
147  if (isset($_POST["ctrlName"]) && $_POST["ctrlName"] !== "") {
148  $namespace="";
149  $resource=$_POST["resource"];
150  $route=$_POST["route"];
151  $restControllerNS=RestServer::getRestNamespace();
152  $restControllersDir=ROOT . DS . str_replace("\\", DS, $restControllerNS);
153  UFileSystem::safeMkdir($restControllersDir);
154  $controllerName=\ucfirst($_POST["ctrlName"]);
155  $filename=$restControllersDir . DS . $controllerName . ".php";
156  if (!\file_exists($filename)) {
157  $frameworkDir=Startup::getFrameworkDir();
158  if ($restControllerNS !== "")
159  $namespace="namespace " . $restControllerNS . ";";
160  UFileSystem::openReplaceWriteFromTemplateFile($frameworkDir . "/admin/templates/restController.tpl", $filename, [ "%resource%" => $resource,"%route%" => $route,"%controllerName%" => $controllerName,"%namespace%" => $namespace ]);
161  echo $this->showSimpleMessage("The <b>" . $controllerName . "</b> Rest controller has been created in <b>" . UFileSystem::cleanPathname($filename) . "</b>.", "success", "checkmark circle", 30000, "msgGlobal");
162  if (isset($_POST["re-init"])) {
163  $this->initRestCache(false);
164  }
165  } else {
166  echo $this->showSimpleMessage("The file <b>" . $filename . "</b> already exists.<br>Can not create the <b>" . $controllerName . "</b> Rest controller!", "warning", "warning circle", 30000, "msgGlobal");
167  }
168  $this->_refreshRest(true);
169  }
170  $this->jquery->exec("$('#div-new-resource').hide();$('#divRest').show();", true);
171  echo $this->jquery->compile($this->view);
172  }
173  }
174 
175  protected function _addRestDataTableBehavior() {
176  $this->jquery->click("._toTest", "if(!$(this).hasClass('active')){
177  \$(this).closest('tr').after('<tr class=\"active\"><td id=\"sub-td'+$(this).closest('tr').attr('id')+'\" colspan=\"'+$(this).closest('tr').children('td').length+'\">test</td></tr>');
178  $(this).addClass('active').removeClass('visibleover');}else{
179  $(this).removeClass('active').addClass('visibleover');
180  $(this).closest('tr').find('.ui.icon.help').transition('hide');
181  $('#sub-td'+$(this).closest('tr').attr('id')).remove();
182  }", false, false, true);
183  $this->jquery->click("._showMsgHelp", '$("#"+$(this).attr("data-show")).transition();');
184  $this->jquery->postOnClick("._toTest", $this->_getAdminFiles()->getAdminBaseRoute() . "/_displayRestFormTester", "{resource:$(this).attr('data-resource'),controller:$(this).attr('data-controller'),action:$(this).attr('data-action'),path:$(this).closest('tr').attr('data-ajax')}", "'#sub-td'+$(self).closest('tr').attr('id')", [ "ajaxTransition" => "random","stopPropagation" => true,"jsCondition" => "!$(self).hasClass('active')" ]);
185  $this->jquery->exec("addToken=function(jqXHR){
186  if(jqXHR.getResponseHeader('authorization')!=null && jqXHR.getResponseHeader('authorization').trim().startsWith('Bearer')){
187  var bearer=jqXHR.getResponseHeader('authorization').trim().slice(7);
188  $('#access-token').val(bearer);
189  $('#access-token').trigger('change');
190  }
191  }", true);
192  }
193 
194  public function _runRestMethod() {
195  $headers=$this->getRestRequestHeaders();
196  $method=$_POST["method"];
197  $path=$_POST["path"];
198  $formId="sub-tddtRest-tr-" . JString::cleanIdentifier($_POST["pathId"]);
199  $this->jquery->ajax($method, $path, "#" . $formId . " ._restResponse", [ "jsCallback" => "$('#" . $formId . " ._restResponse').html(JSON.stringify(data,null,2))","complete" => "var status = { 200 : 'green', 401 : 'orange', 403 : 'brown', 404 : 'black', 500 : 'red' };
200  var headers=jqXHR.getAllResponseHeaders();
201  headers=headers.split(/\\r\\n/);
202  var bHeaders=[];
203  $.each(headers,function(index,header){
204  var vp=header.split(':');
205  if(vp[0]!='')
206  bHeaders.push('\"'+vp[0]+'\":\"'+vp[1]+'\"');
207  });
208  headers=$.parseJSON('{'+bHeaders.join(',')+'}');
209  $('#" . $formId . " ._responseHeaders').html(JSON.stringify(headers,null,2));
210  if(jqXHR.responseText==null){
211  $('#" . $formId . " ._restResponse').html('The response is empty');
212  }else if(jqXHR.status!=200){
213  $('#" . $formId . " ._restResponse').html(jqXHR.responseText);
214  }
215  $('#" . $formId . " ._statusText').html(jqXHR.statusText);
216  $('#" . $formId . " ._status').html(jqXHR.status);
217  $('#" . $formId . " ._status').removeClass('red black brown orange green').addClass(status[jqXHR.status]);
218  addToken(jqXHR);","dataType" => "json","headers" => $headers,"params" => $this->getRestRequestParams() ]);
219  echo '<div><h5 class="ui top block attached header">Response headers</h5><div class="ui attached segment"><pre style="font-size: 10px;" class="_responseHeaders"></pre></div></div>';
220  echo $this->jquery->compile($this->view);
221  }
222 
223  protected function getRestRequestHeaders() {
224  $result=[ '"Authorization": "Bearer "+$("#access-token").val()' ];
225  if (isset($_POST["headers"])) {
226  $headers=urldecode($_POST["headers"]);
227  \parse_str($headers, $output);
228  $this->_getParamsForJSON($result, $output);
229  }
230  return "{" . \implode(",", $result) . "}";
231  }
232 
233  protected function getRestRequestParams() {
234  $result=[ ];
235  if (isset($_POST["params"])) {
236  $headers=urldecode($_POST["params"]);
237  \parse_str($headers, $output);
238  $this->_getParamsForJSON($result, $output);
239  }
240  return "{" . \implode(",", $result) . "}";
241  }
242 
243  protected function _getParamsForJSON(&$result, $params) {
244  if (isset($params["name"])) {
245  $names=$params["name"];
246  $values=$params["value"];
247  $count=\sizeof($names);
248  for($i=0; $i < $count; $i++) {
249  $name=$names[$i];
250  if (UString::isNotNull($name)) {
251  if (isset($values[$i]))
252  $result[]='"' . $name . '": "' . \addslashes($values[$i]) . '"';
253  }
254  }
255  }
256  }
257 
258  public function _saveToken() {
259  if (isset($_POST["_token"]))
260  $_SESSION["_token"]=$_POST["_token"];
261  }
262 
263  public function _saveRequestParams($type="parameter") {
264  $keys=$_POST["name"];
265  $values=$_POST["value"];
266  $toUpdate=$_POST["toUpdate"];
267  $frm=$this->jquery->semantic()->htmlForm($toUpdate);
268  $frm->setSize("mini");
269  $count=\sizeof($values);
270  for($i=0; $i < $count; $i++) {
271  if (JString::isNull($keys[$i])) {
272  unset($keys[$i]);
273  unset($values[$i]);
274  }
275  }
276  $keys=\array_values($keys);
277  $values=\array_values($values);
278  $count=\sizeof($values);
279  if ($count > 0) {
280  $fields=$frm->addFields();
281  $fields->addElement("", "Name", "", "div", "ui label mini black pointing below");
282  $fields->addElement("", "Value", "", "div", "ui label mini black pointing below");
283  for($i=0; $i < $count; $i++) {
284  $fields=$frm->addFields();
285  $fields->addInput("name[]", "", "text", $keys[$i])->setIdentifier("name-" . $i);
286  $input=$fields->addInput("value[]", "", "text", $values[$i])->setIdentifier("value-" . $i);
287  $input->addAction("", true, "remove")->addClass("icon basic mini _deleteParameter");
288  }
289  } else {
290  $frm->addItem(new HtmlLabel("", "No " . $type . "s"));
291  }
292  $this->jquery->click("._deleteParameter", "
293  $(this).parents('.fields').remove();
294  if($('#" . $toUpdate . "').find('.fields').length==1){
295  $('#" . $toUpdate . "').children('.fields').remove();
296  $('#" . $toUpdate . "').append('<div class=\"ui label\">No " . $type . "s</div>');
297  }
298  ", true, true, true);
299  echo $frm;
300  echo $this->jquery->compile($this->view);
301  }
302 }
static isPost()
Returns true if the request is sent by the POST method.
Definition: URequest.php:91
static docMethodParser($classname, $method)
Definition: DocParser.php:120
showSimpleMessage($content, $type, $icon="info", $timeout=NULL, $staticName=null)
static getModels(&$config, $silent=false)
static openReplaceWriteFromTemplateFile($source, $destination, $keyAndValues)
Definition: UFileSystem.php:56
static initCache(&$config, $type="all", $silent=false)