Account Suspended
Account Suspended
This Account has been suspended.
Contact your hosting provider for more information.
 All Data Structures Functions Variables Pages
ZurmoModuleApiController.php
1 <?php
2  /*********************************************************************************
3  * Zurmo is a customer relationship management program developed by
4  * Zurmo, Inc. Copyright (C) 2017 Zurmo Inc.
5  *
6  * Zurmo is free software; you can redistribute it and/or modify it under
7  * the terms of the GNU Affero General Public License version 3 as published by the
8  * Free Software Foundation with the addition of the following permission added
9  * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
10  * IN WHICH THE COPYRIGHT IS OWNED BY ZURMO, ZURMO DISCLAIMS THE WARRANTY
11  * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
12  *
13  * Zurmo is distributed in the hope that it will be useful, but WITHOUT
14  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
15  * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Affero General Public License along with
19  * this program; if not, see http://www.gnu.org/licenses or write to the Free
20  * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21  * 02110-1301 USA.
22  *
23  * You can contact Zurmo, Inc. with a mailing address at 27 North Wacker Drive
24  * Suite 370 Chicago, IL 60606. or at email address contact@zurmo.com.
25  *
26  * The interactive user interfaces in original and modified versions
27  * of this program must display Appropriate Legal Notices, as required under
28  * Section 5 of the GNU Affero General Public License version 3.
29  *
30  * In accordance with Section 7(b) of the GNU Affero General Public License version 3,
31  * these Appropriate Legal Notices must retain the display of the Zurmo
32  * logo and Zurmo copyright notice. If the display of the logo is not reasonably
33  * feasible for technical reasons, the Appropriate Legal Notices must display the words
34  * "Copyright Zurmo Inc. 2017. All rights reserved".
35  ********************************************************************************/
36 
43  {
44  const RIGHTS_FILTER_PATH = 'application.modules.api.utils.ApiRightsControllerFilter';
45 
46  public function filters()
47  {
48  $filters = array(
49  'apiRequest'
50  );
51  return array_merge($filters, parent::filters());
52  }
53 
54  public function filterApiRequest($filterChain)
55  {
56  try
57  {
58  $filterChain->run();
59  }
60  catch (Exception $e)
61  {
62  $resultClassName = Yii::app()->apiRequest->getResultClassName();
63  $result = new $resultClassName(ApiResponse::STATUS_FAILURE, null, $e->getMessage(), null);
64  Yii::app()->apiHelper->sendResponse($result);
65  }
66  }
67 
72  public function actionRead()
73  {
74  $params = Yii::app()->apiRequest->getParams();
75  if (!isset($params['id']))
76  {
77  $message = Zurmo::t('ZurmoModule', 'The ID specified was invalid.');
78  throw new ApiException($message);
79  }
80  $result = $this->processRead((int)$params['id']);
81  Yii::app()->apiHelper->sendResponse($result);
82  }
83 
87  public function actionList()
88  {
89  $params = Yii::app()->apiRequest->getParams();
90  $result = $this->processList($params);
91  Yii::app()->apiHelper->sendResponse($result);
92  }
93 
97  public function actionListAttributes()
98  {
99  $params = Yii::app()->apiRequest->getParams();
100  $result = $this->processListAttributes($params);
101  Yii::app()->apiHelper->sendResponse($result);
102  }
103 
107  public function actionSearch()
108  {
109  $params = Yii::app()->apiRequest->getParams();
110  $result = $this->processSearch($params);
111  Yii::app()->apiHelper->sendResponse($result);
112  }
113 
118  public function actionCreate()
119  {
120  $params = Yii::app()->apiRequest->getParams();
121  if (!isset($params['data']))
122  {
123  $message = Zurmo::t('ZurmoModule', 'Please provide data.');
124  try
125  {
126  $this->checkPostSizeExceeded();
127  }
128  catch (ApiException $e)
129  {
130  $message = $e->getMessage();
131  }
132  throw new ApiException($message);
133  }
134  $result = $this->processCreate($params['data']);
135  Yii::app()->apiHelper->sendResponse($result);
136  }
137 
142  public function actionUpdate()
143  {
144  $params = Yii::app()->apiRequest->getParams();
145  if (!isset($params['data']))
146  {
147  $message = Zurmo::t('ZurmoModule', 'Please provide data.');
148  try
149  {
150  $this->checkPostSizeExceeded();
151  }
152  catch (ApiException $e)
153  {
154  $message = $e->getMessage();
155  }
156  throw new ApiException($message);
157  }
158  if (!isset($params['id']) || intval($params['id']) <= 0)
159  {
160  $message = Zurmo::t('ZurmoModule', 'The ID specified was invalid.');
161  throw new ApiException($message);
162  }
163  $result = $this->processUpdate((int)$params['id'], $params['data']);
164  Yii::app()->apiHelper->sendResponse($result);
165  }
166 
171  public function actionDelete()
172  {
173  $params = Yii::app()->apiRequest->getParams();
174  if (!isset($params['id']))
175  {
176  $message = Zurmo::t('ZurmoModule', 'The ID specified was invalid.');
177  throw new ApiException($message);
178  }
179  $result = $this->processDelete((int)$params['id']);
180  Yii::app()->apiHelper->sendResponse($result);
181  }
182 
186  public function actionAddRelation()
187  {
188  $params = Yii::app()->apiRequest->getParams();
189  $result = $this->processAddRelation($params);
190  Yii::app()->apiHelper->sendResponse($result);
191  }
192 
196  public function actionRemoveRelation()
197  {
198  $params = Yii::app()->apiRequest->getParams();
199  $result = $this->processRemoveRelation($params);
200  Yii::app()->apiHelper->sendResponse($result);
201  }
202 
206  protected function getModelName()
207  {
208  return $this->getModule()->getPrimaryModelName();
209  }
210 
217  protected function processRead($id)
218  {
219  assert('is_int($id)');
220  $modelClassName = $this->getModelName();
221 
222  try
223  {
224  $model = $modelClassName::getById($id);
225  }
226  catch (NotFoundException $e)
227  {
228  $message = Zurmo::t('ZurmoModule', 'The ID specified was invalid.');
229  throw new ApiException($message);
230  }
231 
232  try
233  {
235  }
236  catch (SecurityException $e)
237  {
238  $message = $e->getMessage();
239  throw new ApiException($message);
240  }
241 
242  try
243  {
244  $data = static::getModelToApiDataUtilData($model);
245  $resultClassName = Yii::app()->apiRequest->getResultClassName();
246  $result = new $resultClassName(ApiResponse::STATUS_SUCCESS, $data, null, null);
247  }
248  catch (Exception $e)
249  {
250  $message = $e->getMessage();
251  throw new ApiException($message);
252  }
253  return $result;
254  }
255 
256  protected static function getSearchFormClassName()
257  {
258  return null;
259  }
260 
267  protected function processList($params)
268  {
269  $modelClassName = $this->getModelName();
270  $searchFormClassName = static::getSearchFormClassName();
271 
272  try
273  {
274  $filterParams = array();
275 
276  if (strtolower($_SERVER['REQUEST_METHOD']) != 'post')
277  {
278  if (isset($params['filter']) && $params['filter'] != '')
279  {
280  parse_str($params['filter'], $filterParams);
281  }
282  }
283  else
284  {
285  $filterParams = $params['data'];
286  }
287 
288  $pageSize = Yii::app()->pagination->getGlobalValueByType('apiListPageSize');
289 
290  if (isset($filterParams['pagination']['pageSize']))
291  {
292  $pageSize = (int)$filterParams['pagination']['pageSize'];
293  }
294 
295  if (isset($filterParams['pagination']['page']))
296  {
297  $_GET[$modelClassName . '_page'] = (int)$filterParams['pagination']['page'];
298  }
299 
300  if (isset($filterParams['sort']))
301  {
302  $_GET[$modelClassName . '_sort'] = $filterParams['sort'];
303  }
304 
305  if (isset($filterParams['search']) && isset($searchFormClassName))
306  {
307  $_GET[$searchFormClassName] = $filterParams['search'];
308  }
309  if (isset($filterParams['dynamicSearch']) &&
310  isset($searchFormClassName) &&
311  !empty($filterParams['dynamicSearch']['dynamicClauses']) &&
312  !empty($filterParams['dynamicSearch']['dynamicStructure']))
313  {
314  // Convert model ids into item ids, so we can perform dynamic search
315  DynamicSearchUtil::resolveDynamicSearchClausesForModelIdsNeedingToBeItemIds($modelClassName, $filterParams['dynamicSearch']['dynamicClauses']);
316  $_GET[$searchFormClassName]['dynamicClauses'] = $filterParams['dynamicSearch']['dynamicClauses'];
317  $_GET[$searchFormClassName]['dynamicStructure'] = $filterParams['dynamicSearch']['dynamicStructure'];
318  }
319 
320  $model = new $modelClassName(false);
321  if (isset($searchFormClassName))
322  {
323  $searchForm = new $searchFormClassName($model);
324  }
325  else
326  {
327  throw new NotSupportedException();
328  }
329  $stateMetadataAdapterClassName = $this->resolveStateMetadataAdapterClassName();
330  $dataProvider = $this->makeRedBeanDataProviderByDataCollection(
331  $searchForm,
332  $pageSize,
333  $stateMetadataAdapterClassName
334  );
335 
336  if (isset($filterParams['pagination']['page']) && (int)$filterParams['pagination']['page'] > 0)
337  {
338  $currentPage = (int)$filterParams['pagination']['page'];
339  }
340  else
341  {
342  $currentPage = 1;
343  }
344 
345  $totalItems = $dataProvider->getTotalItemCount();
346  $data = array();
347  $data['totalCount'] = $totalItems;
348  $data['currentPage'] = $currentPage;
349  if ($totalItems > 0)
350  {
351  $formattedData = $dataProvider->getData();
352  foreach ($formattedData as $model)
353  {
354  $data['items'][] = static::getModelToApiDataUtilData($model);
355  }
356  $result = new ApiResult(ApiResponse::STATUS_SUCCESS, $data, null, null);
357  }
358  else
359  {
360  $result = new ApiResult(ApiResponse::STATUS_SUCCESS, $data, null, null);
361  }
362  }
363  catch (Exception $e)
364  {
365  $message = $e->getMessage();
366  throw new ApiException($message);
367  }
368  return $result;
369  }
370 
377  protected function processListAttributes($params)
378  {
379  $data = array();
380  try
381  {
382  $modelClassName = $this->getModelName();
383  $model = new $modelClassName();
384  $adapter = new ModelAttributesAdapter($model);
385  $customAttributes = ArrayUtil::subValueSort($adapter->getCustomAttributes(), 'attributeLabel', 'asort');
386  $standardAttributes = ArrayUtil::subValueSort($adapter->getStandardAttributes(), 'attributeLabel', 'asort');
387  $allAttributes = array_merge($customAttributes, $standardAttributes);
388  $data['items'] = $allAttributes;
389  $result = new ApiResult(ApiResponse::STATUS_SUCCESS, $data, null, null);
390  }
391  catch (Exception $e)
392  {
393  $message = $e->getMessage();
394  throw new ApiException($message);
395  }
396  return $result;
397  }
398 
405  protected function processSearch($params)
406  {
407  try
408  {
409  $filterParams = array();
410  if (strtolower($_SERVER['REQUEST_METHOD']) != 'post')
411  {
412  if (isset($params['filter']) && $params['filter'] != '')
413  {
414  parse_str($params['filter'], $filterParams);
415  }
416  }
417  else
418  {
419  $filterParams = $params['data'];
420  }
421  // Check if modelClassName exist and if it is subclass of RedBeanModel
422  if (@class_exists($filterParams['search']['modelClassName']))
423  {
424  $modelClassName = $filterParams['search']['modelClassName'];
425  @$modelClass = new $modelClassName();
426  if (!($modelClass instanceof RedBeanModel))
427  {
428  $message = Zurmo::t('ZurmoModule', '{modelClassName} should be subclass of RedBeanModel.',
429  array('{modelClassName}' => $modelClassName));
430  throw new NotSupportedException($message);
431  }
432  }
433  else
434  {
435  $message = Zurmo::t('ZurmoModule', "{modelClassName} class does not exist.",
436  array('{modelClassName}' => $filterParams['search']['modelClassName']));
437  throw new NotSupportedException($message);
438  }
439  $pageSize = Yii::app()->pagination->getGlobalValueByType('apiListPageSize');
440  if (isset($filterParams['pagination']['pageSize']))
441  {
442  $pageSize = (int)$filterParams['pagination']['pageSize'];
443  }
444 
445  // Get offset. Please note that API client provide page number, and we need to convert it into offset,
446  // which is parameter of RedBeanModel::getSubset function
447  if (isset($filterParams['pagination']['page']) && (int)$filterParams['pagination']['page'] > 0)
448  {
449  $currentPage = (int)$filterParams['pagination']['page'];
450  }
451  else
452  {
453  $currentPage = 1;
454  }
455  $offset = $this->getOffsetFromCurrentPageAndPageSize($currentPage, $pageSize);
456  $sort = null;
457  if (isset($filterParams['sort']))
458  {
459  $sort = $filterParams['sort'];
460  }
461 
462  $stateMetadataAdapterClassName = $this->resolveStateMetadataAdapterClassName();
463  if ($stateMetadataAdapterClassName != null)
464  {
465  $stateMetadataAdapter = new $stateMetadataAdapterClassName($filterParams['search']['searchAttributeData']);
466  $filterParams['search']['searchAttributeData'] = $stateMetadataAdapter->getAdaptedDataProviderMetadata();
467  $filterParams['search']['searchAttributeData']['structure'] = '(' . $filterParams['search']['searchAttributeData']['structure'] . ')';
468  }
469 
470  $joinTablesAdapter = new RedBeanModelJoinTablesQueryAdapter($modelClassName);
471  $where = RedBeanModelDataProvider::makeWhere($modelClassName,
472  $filterParams['search']['searchAttributeData'], $joinTablesAdapter);
473 
474  $results = $modelClassName::getSubset($joinTablesAdapter,
475  $offset, $pageSize, $where, $sort, $modelClassName, true);
476  $totalItems = $modelClassName::getCount($joinTablesAdapter, $where, null, true);
477 
478  $data = array();
479  $data['totalCount'] = $totalItems;
480  $data['currentPage'] = $currentPage;
481  if ($totalItems > 0)
482  {
483  foreach ($results as $model)
484  {
485  $data['items'][] = static::getModelToApiDataUtilData($model);
486  }
487  $result = new ApiResult(ApiResponse::STATUS_SUCCESS, $data, null, null);
488  }
489  else
490  {
491  $result = new ApiResult(ApiResponse::STATUS_SUCCESS, $data, null, null);
492  }
493  }
494  catch (Exception $e)
495  {
496  $message = $e->getMessage();
497  throw new ApiException($message);
498  }
499  return $result;
500  }
501 
507  protected function getOffsetFromCurrentPageAndPageSize($currentPage, $pageSize)
508  {
509  $offset = (int)(($currentPage - 1) * $pageSize);
510  if ($offset == 0)
511  {
512  $offset = null;
513  }
514  return $offset;
515  }
516 
523  protected function processAddRelation($params)
524  {
525  $modelClassName = $this->getModelName();
526  try
527  {
528  $data = array();
529  if (isset($params['data']) && $params['data'] != '')
530  {
531  parse_str($params['data'], $data);
532  }
533  $relationName = $data['relationName'];
534  $modelId = $data['id'];
535  $relatedId = $data['relatedId'];
536  $model = $modelClassName::getById(intval($modelId));
537  $relatedModelClassName = $model->getRelationModelClassName($relationName);
538  $relatedModel = $relatedModelClassName::getById(intval($relatedId));
539 
540  if ($model->getRelationType($relationName) == RedBeanModel::HAS_MANY ||
541  $model->getRelationType($relationName) == RedBeanModel::MANY_MANY)
542  {
543  $model->{$relationName}->add($relatedModel);
544 
545  if ($model->save())
546  {
547  $result = new ApiResult(ApiResponse::STATUS_SUCCESS, null);
548  }
549  else
550  {
551  $message = Zurmo::t('ZurmoModule', 'Could not save relation.');
552  throw new ApiException($message);
553  }
554  }
555  else
556  {
557  $message = Zurmo::t('ZurmoModule', 'Could not use this API call for HAS_ONE relationships.');
558  throw new ApiException($message);
559  }
560  }
561  catch (Exception $e)
562  {
563  $message = $e->getMessage();
564  throw new ApiException($message);
565  }
566  return $result;
567  }
568 
575  protected function processRemoveRelation($params)
576  {
577  $modelClassName = $this->getModelName();
578  try
579  {
580  $data = array();
581  if (isset($params['data']) && $params['data'] != '')
582  {
583  parse_str($params['data'], $data);
584  }
585  $relationName = $data['relationName'];
586  $modelId = $data['id'];
587  $relatedId = $data['relatedId'];
588 
589  $model = $modelClassName::getById(intval($modelId));
590  $relatedModelClassName = $model->getRelationModelClassName($relationName);
591  $relatedModel = $relatedModelClassName::getById(intval($relatedId));
592  if ($model->getRelationType($relationName) == RedBeanModel::HAS_MANY ||
593  $model->getRelationType($relationName) == RedBeanModel::MANY_MANY)
594  {
595  $model->{$relationName}->remove($relatedModel);
596  if ($model->save())
597  {
598  $result = new ApiResult(ApiResponse::STATUS_SUCCESS, null);
599  }
600  else
601  {
602  $message = Zurmo::t('ZurmoModule', 'Could not remove relation.');
603  throw new ApiException($message);
604  }
605  }
606  else
607  {
608  $message = Zurmo::t('ZurmoModule', 'Could not use this API call for HAS_ONE relationships.');
609  throw new ApiException($message);
610  }
611  }
612  catch (Exception $e)
613  {
614  $message = $e->getMessage();
615  throw new ApiException($message);
616  }
617  return $result;
618  }
619 
626  protected function processCreate($data)
627  {
628  $modelClassName = $this->getModelName();
629  try
630  {
631  if (isset($data['modelRelations']))
632  {
633  $modelRelations = $data['modelRelations'];
634  unset($data['modelRelations']);
635  }
636  $model = new $modelClassName();
637  $this->setModelScenarioFromData($model, $data);
638  $model = $this->attemptToSaveModelFromData($model, $data, null, false);
639  $id = $model->id;
640  $model->forget();
641  if (!count($model->getErrors()))
642  {
643  if (isset($modelRelations) && count($modelRelations))
644  {
645  try
646  {
647  $this->manageModelRelations($model, $modelRelations);
648  $model->save();
649  }
650  catch (Exception $e)
651  {
652  $model->delete();
653  $message = $e->getMessage();
654  throw new ApiException($message);
655  }
656  }
657  $model = $modelClassName::getById($id);
658  $data = static::getModelToApiDataUtilData($model);
659  $result = new ApiResult(ApiResponse::STATUS_SUCCESS, $data, null, null);
660  }
661  else
662  {
663  $errors = $model->getErrors();
664  $message = Zurmo::t('ZurmoModule', 'Model was not created.');
665  $result = new ApiResult(ApiResponse::STATUS_FAILURE, null, $message, $errors);
666  }
667  }
668  catch (Exception $e)
669  {
670  $message = $e->getMessage();
671  throw new ApiException($message);
672  }
673  return $result;
674  }
675 
683  protected function processUpdate($id, $data)
684  {
685  assert('is_int($id)');
686  $modelClassName = $this->getModelName();
687 
688  if (isset($data['modelRelations']))
689  {
690  $modelRelations = $data['modelRelations'];
691  unset($data['modelRelations']);
692  }
693 
694  try
695  {
696  $model = $modelClassName::getById($id);
697  $this->setModelScenarioFromData($model, $data);
698  }
699  catch (NotFoundException $e)
700  {
701  $message = Zurmo::t('ZurmoModule', 'The ID specified was invalid.');
702  throw new ApiException($message);
703  }
704 
705  try
706  {
708  }
709  catch (SecurityException $e)
710  {
711  $message = $e->getMessage();
712  throw new ApiException($message);
713  }
714 
715  try
716  {
717  $model = $this->attemptToSaveModelFromData($model, $data, null, false);
718  $id = $model->id;
719  if (!count($model->getErrors()))
720  {
721  if (isset($modelRelations) && count($modelRelations))
722  {
723  try
724  {
725  $this->manageModelRelations($model, $modelRelations);
726  $model->save();
727  }
728  catch (Exception $e)
729  {
730  $message = Zurmo::t('ZurmoModule', 'Model was updated, but there were issues with relations.');
731  $message .= ' ' . $e->getMessage();
732  throw new ApiException($message);
733  }
734  }
735 
736  $model = $modelClassName::getById($id);
737  $data = static::getModelToApiDataUtilData($model);
738  $result = new ApiResult(ApiResponse::STATUS_SUCCESS, $data, null, null);
739  }
740  else
741  {
742  $errors = $model->getErrors();
743  $message = Zurmo::t('ZurmoModule', 'Model was not updated.');
744  // To-Do: How to pass $errors and $message to exception
745  //throw new ApiException($message);
746  $result = new ApiResult(ApiResponse::STATUS_FAILURE, null, $message, $errors);
747  }
748  }
749  catch (Exception $e)
750  {
751  $message = $e->getMessage();
752  throw new ApiException($message);
753  }
754  return $result;
755  }
756 
762  protected function resolveModelScenario(array & $data)
763  {
764  if (isset($data['modelScenario']) && $data['modelScenario'] != '')
765  {
766  $scenarioName = $data['modelScenario'];
767  unset($data['modelScenario']);
768  return $scenarioName;
769  }
770  return null;
771  }
772 
778  protected function setModelScenarioFromData(RedBeanModel $model, array & $data)
779  {
780  $scenarioName = $this->resolveModelScenario($data);
781  if (isset($scenarioName) && $scenarioName != '')
782  {
783  $model->setScenario($scenarioName);
784  }
785  }
786 
793  protected function manageModelRelations($model, $modelRelations)
794  {
795  try
796  {
797  if (isset($modelRelations) && !empty($modelRelations))
798  {
799  foreach ($modelRelations as $modelRelation => $relations)
800  {
801  if ($model->isAttribute($modelRelation) &&
802  ($model->getRelationType($modelRelation) == RedBeanModel::HAS_MANY ||
803  $model->getRelationType($modelRelation) == RedBeanModel::MANY_MANY))
804  {
805  foreach ($relations as $relation)
806  {
807  $relatedModelClassName = $relation['modelClassName'];
808  try
809  {
810  $relatedModel = $relatedModelClassName::getById(intval($relation['modelId']));
811  }
812  catch (Exception $e)
813  {
814  $message = Zurmo::t('ZurmoModule', 'The related model ID specified was invalid.');
815  throw new NotFoundException($message);
816  }
817 
818  if ($relation['action'] == 'add')
819  {
820  $model->{$modelRelation}->add($relatedModel);
821  }
822  elseif ($relation['action'] == 'remove')
823  {
824  $model->{$modelRelation}->remove($relatedModel);
825  }
826  else
827  {
828  $message = Zurmo::t('ZurmoModule', 'Unsupported action.');
829  throw new NotSupportedException($message);
830  }
831  }
832  }
833  else
834  {
835  $message = Zurmo::t('ZurmoModule', 'You can add relations only for HAS_MANY and MANY_MANY relations.');
836  throw new NotSupportedException($message);
837  }
838  }
839  }
840  }
841  catch (Exception $e)
842  {
843  $message = $e->getMessage();
844  throw new ApiException($message);
845  }
846  return true;
847  }
848 
855  protected function processDelete($id)
856  {
857  assert('is_int($id)');
858  $modelClassName = $this->getModelName();
859 
860  try
861  {
862  $model = $modelClassName::getById($id);
863  }
864  catch (NotFoundException $e)
865  {
866  $message = Zurmo::t('ZurmoModule', 'The ID specified was invalid.');
867  throw new ApiException($message);
868  }
869 
870  try
871  {
873  }
874  catch (SecurityException $e)
875  {
876  $message = $e->getMessage();
877  throw new ApiException($message);
878  }
879 
880  try
881  {
882  $model->delete();
883  $result = new ApiResult(ApiResponse::STATUS_SUCCESS, null);
884  }
885  catch (Exception $e)
886  {
887  $message = $e->getMessage();
888  throw new ApiException($message);
889  }
890  return $result;
891  }
892 
897  protected function attemptToSaveModelFromData($model, $data, $redirectUrlParams = null, $redirect = true)
898  {
899  assert('is_array($data)');
900  assert('$redirectUrlParams == null || is_array($redirectUrlParams) || is_string($redirectUrlParams)');
901  $savedSucessfully = false;
902  $modelToStringValue = null;
903 
904  if (isset($data))
905  {
906  $this->preAttemptToSaveModelFromDataHook($model, $data);
907  $controllerUtil = new ZurmoControllerUtil();
908  $model = $controllerUtil->saveModelFromSanitizedData($data, $model, $savedSucessfully,
909  $modelToStringValue, false);
910  }
911  if ($savedSucessfully && $redirect)
912  {
913  $this->actionAfterSuccessfulModelSave($model, $modelToStringValue, $redirectUrlParams);
914  }
915  return $model;
916  }
917 
923  protected function preAttemptToSaveModelFromDataHook(RedBeanModel $model, array & $data)
924  {
925  }
926 
931  protected static function getModelToApiDataUtil()
932  {
933  return 'RedBeanModelToApiDataUtil';
934  }
935 
941  protected static function getModelToApiDataUtilData(RedBeanModel $model)
942  {
943  $dataUtil = static::getModelToApiDataUtil();
944  $redBeanModelToApiDataUtil = new $dataUtil($model);
945  $data = $redBeanModelToApiDataUtil->getData();
946  static::resolveIncludingAdditionalData($data);
947  return $data;
948  }
949 
955  protected static function resolveIncludingAdditionalData(Array & $data)
956  {
957  }
958 
964  {
965  // In case of ContactState model, we can't use Module::getStateMetadataAdapterClassName() function,
966  // because it references to Contact model, so we defined new function
967  // ContactsContactStateApiController::getStateMetadataAdapterClassName() which return null.
968  if (method_exists($this, 'getStateMetadataAdapterClassName'))
969  {
970  $stateMetadataAdapterClassName = $this->getStateMetadataAdapterClassName();
971  }
972  else
973  {
974  $stateMetadataAdapterClassName = $this->getModule()->getStateMetadataAdapterClassName();
975  }
976  return $stateMetadataAdapterClassName;
977  }
978 
985  protected function processGetDeletedItems($params)
986  {
987  try
988  {
989  $modelClassName = $this->getModelName();
990  $stateMetadataAdapterClassName = $this->resolveStateMetadataAdapterClassName();
991 
992  if (!isset($params['sinceDateTime']))
993  {
994  $sinceTimestamp = 0;
995  }
996  else
997  {
998  if (DateTimeUtil::isValidDbFormattedDateTime($params['sinceDateTime']))
999  {
1000  $sinceTimestamp = DateTimeUtil::convertDbFormatDateTimeToTimestamp($params['sinceDateTime']);
1001  }
1002  else
1003  {
1004  $message = 'sinceDateTime format is not correct. sinceDateTime should be in "YYYY-MM-DD HH:MM:SS" format';
1005  throw new ApiException($message);
1006  }
1007  }
1008 
1009  $pageSize = Yii::app()->pagination->getGlobalValueByType('apiListPageSize');
1010  if (isset($params['pagination']['pageSize']))
1011  {
1012  $pageSize = (int)$params['pagination']['pageSize'];
1013  }
1014 
1015  // Get offset. Please note that API client provide page number, and we need to convert it into offset,
1016  // which is parameter of RedBeanModel::getSubset function
1017  if (isset($params['pagination']['page']) && (int)$params['pagination']['page'] > 0)
1018  {
1019  $currentPage = (int)$params['pagination']['page'];
1020  }
1021  else
1022  {
1023  $currentPage = 1;
1024  }
1025  $offset = $this->getOffsetFromCurrentPageAndPageSize($currentPage, $pageSize);
1026 
1027  $modelIds = ModelStateChangesSubscriptionUtil::getDeletedModelIds('API', $modelClassName, $pageSize, $offset, $sinceTimestamp, $stateMetadataAdapterClassName);
1028  $totalItems = ModelStateChangesSubscriptionUtil::getDeletedModelsCount('API', $modelClassName, $sinceTimestamp, $stateMetadataAdapterClassName);
1029 
1030  $data = array(
1031  'totalCount' => $totalItems,
1032  'pageSize' => $pageSize,
1033  'currentPage' => $currentPage
1034  );
1035 
1036  if ($totalItems > 0 && is_array($modelIds) && !empty($modelIds))
1037  {
1038  foreach ($modelIds as $modelId)
1039  {
1040  $data['items'][] = $modelId;
1041  }
1042  $result = new ApiResult(ApiResponse::STATUS_SUCCESS, $data, null, null);
1043  }
1044  else
1045  {
1046  $result = new ApiResult(ApiResponse::STATUS_SUCCESS, $data, null, null);
1047  }
1048  }
1049  catch (Exception $e)
1050  {
1051  $message = $e->getMessage();
1052  throw new ApiException($message);
1053  }
1054  return $result;
1055  }
1056 
1063  protected function processGetCreatedItems($params)
1064  {
1065  try
1066  {
1067  $modelClassName = $this->getModelName();
1068  $stateMetadataAdapterClassName = $this->resolveStateMetadataAdapterClassName();
1069 
1070  if (!isset($params['sinceDateTime']))
1071  {
1072  $sinceTimestamp = 0;
1073  }
1074  else
1075  {
1076  if (DateTimeUtil::isValidDbFormattedDateTime($params['sinceDateTime']))
1077  {
1078  $sinceTimestamp = DateTimeUtil::convertDbFormatDateTimeToTimestamp($params['sinceDateTime']);
1079  }
1080  else
1081  {
1082  $message = 'sinceDateTime format is not correct. sinceDateTime should be in "YYYY-MM-DD HH:MM:SS" format';
1083  throw new ApiException($message);
1084  }
1085  }
1086 
1087  $pageSize = Yii::app()->pagination->getGlobalValueByType('apiListPageSize');
1088  if (isset($params['pagination']['pageSize']))
1089  {
1090  $pageSize = (int)$params['pagination']['pageSize'];
1091  }
1092 
1093  // Get offset. Please note that API client provide page number, and we need to convert it into offset,
1094  // which is parameter of RedBeanModel::getSubset function
1095  if (isset($params['pagination']['page']) && (int)$params['pagination']['page'] > 0)
1096  {
1097  $currentPage = (int)$params['pagination']['page'];
1098  }
1099  else
1100  {
1101  $currentPage = 1;
1102  }
1103  $offset = $this->getOffsetFromCurrentPageAndPageSize($currentPage, $pageSize);
1104 
1105  $models = ModelStateChangesSubscriptionUtil::getCreatedModels('API', $modelClassName, $pageSize, $offset, $sinceTimestamp, $stateMetadataAdapterClassName, Yii::app()->user->userModel);
1106  $totalItems = ModelStateChangesSubscriptionUtil::getCreatedModelsCount('API', $modelClassName, $sinceTimestamp, $stateMetadataAdapterClassName, Yii::app()->user->userModel);
1107  $data = array(
1108  'totalCount' => $totalItems,
1109  'pageSize' => $pageSize,
1110  'currentPage' => $currentPage
1111  );
1112 
1113  if (is_array($models) && !empty($models))
1114  {
1115  foreach ($models as $model)
1116  {
1117  $data['items'][] = static::getModelToApiDataUtilData($model);
1118  }
1119  $result = new ApiResult(ApiResponse::STATUS_SUCCESS, $data, null, null);
1120  }
1121  else
1122  {
1123  $result = new ApiResult(ApiResponse::STATUS_SUCCESS, $data, null, null);
1124  }
1125  }
1126  catch (Exception $e)
1127  {
1128  $message = $e->getMessage();
1129  throw new ApiException($message);
1130  }
1131  return $result;
1132  }
1133 
1140  public function processGetModifiedItems($params)
1141  {
1142  try
1143  {
1144  $modelClassName = $this->getModelName();
1145  $stateMetadataAdapterClassName = $this->resolveStateMetadataAdapterClassName();
1146 
1147  if (!isset($params['sinceDateTime']))
1148  {
1149  $sinceTimestamp = 0;
1150  }
1151  else
1152  {
1153  if (DateTimeUtil::isValidDbFormattedDateTime($params['sinceDateTime']))
1154  {
1155  $sinceTimestamp = DateTimeUtil::convertDbFormatDateTimeToTimestamp($params['sinceDateTime']);
1156  }
1157  else
1158  {
1159  $message = 'sinceDateTime format is not correct. sinceDateTime should be in "YYYY-MM-DD HH:MM:SS" format';
1160  throw new ApiException($message);
1161  }
1162  }
1163 
1164  $pageSize = Yii::app()->pagination->getGlobalValueByType('apiListPageSize');
1165  if (isset($params['pagination']['pageSize']))
1166  {
1167  $pageSize = (int)$params['pagination']['pageSize'];
1168  }
1169 
1170  // Get offset. Please note that API client provide page number, and we need to convert it into offset,
1171  // which is parameter of RedBeanModel::getSubset function
1172  if (isset($params['pagination']['page']) && (int)$params['pagination']['page'] > 0)
1173  {
1174  $currentPage = (int)$params['pagination']['page'];
1175  }
1176  else
1177  {
1178  $currentPage = 1;
1179  }
1180  $offset = $this->getOffsetFromCurrentPageAndPageSize($currentPage, $pageSize);
1181  $models = ModelStateChangesSubscriptionUtil::getUpdatedModels($modelClassName, $pageSize, $offset, $sinceTimestamp, $stateMetadataAdapterClassName, Yii::app()->user->userModel);
1182  $totalItems = ModelStateChangesSubscriptionUtil::getUpdatedModelsCount($modelClassName, $sinceTimestamp, $stateMetadataAdapterClassName, Yii::app()->user->userModel);
1183  $data = array(
1184  'totalCount' => $totalItems,
1185  'pageSize' => $pageSize,
1186  'currentPage' => $currentPage
1187  );
1188 
1189  if (is_array($models) && !empty($models))
1190  {
1191  foreach ($models as $model)
1192  {
1193  $data['items'][] = static::getModelToApiDataUtilData($model);
1194  }
1195  $result = new ApiResult(ApiResponse::STATUS_SUCCESS, $data, null, null);
1196  }
1197  else
1198  {
1199  $result = new ApiResult(ApiResponse::STATUS_SUCCESS, $data, null, null);
1200  }
1201  }
1202  catch (Exception $e)
1203  {
1204  $message = $e->getMessage();
1205  throw new ApiException($message);
1206  }
1207  return $result;
1208  }
1209 
1210  public function processGetManyManyRelationshipModels($params)
1211  {
1212  try
1213  {
1214  $modelId = $params['id'];
1215  $relationName = $params['relationName'];
1216  $modelClassName = $params['modelClassName'];
1217 
1218  if (!class_exists($modelClassName, false))
1219  {
1220  $message = Zurmo::t('ZurmoModule', 'The specified class name was invalid.');
1221  throw new ApiException($message);
1222  }
1223  try
1224  {
1225  $model = $modelClassName::getById(intval($modelId));
1226  }
1227  catch (NotFoundException $e)
1228  {
1229  $message = Zurmo::t('ZurmoModule', 'The ID specified was invalid.');
1230  throw new ApiException($message);
1231  }
1232 
1233  $relatedModelClassName = $model->getRelationModelClassName($relationName);
1234  if ($model->isRelation($relationName) &&
1235  $model->getRelationType($relationName) == RedBeanModel::MANY_MANY)
1236  {
1237  $data = array();
1238  foreach ($model->{$relationName} as $item)
1239  {
1240  $data[$relationName][] = array('class' => $relatedModelClassName, 'id' => $item->id);
1241  }
1242  $result = new ApiResult(ApiResponse::STATUS_SUCCESS, $data, null, null);
1243  }
1244  else
1245  {
1246  $message = Zurmo::t('ZurmoModule', 'The specified relationship name does not exist or is not MANY_MANY type.');
1247  throw new ApiException($message);
1248  }
1249  }
1250  catch (Exception $e)
1251  {
1252  $message = $e->getMessage();
1253  throw new ApiException($message);
1254  }
1255  return $result;
1256  }
1257 
1258  protected function checkPostSizeExceeded()
1259  {
1260  $maxPostSize = trim(ini_get('post_max_size'));
1261  $maxPostSizeInBytes = StringUtil::convertToBytes($maxPostSize);
1262  if ($maxPostSizeInBytes > 0)
1263  {
1264  if ($_SERVER['CONTENT_LENGTH'] > $maxPostSizeInBytes)
1265  {
1266  $message = 'Max post size exceeded! Sent ' . $_SERVER['CONTENT_LENGTH'] . ' bytes, but limit is ' . $maxPostSizeInBytes . ' bytes.';
1267  throw new ApiException($message);
1268  }
1269  }
1270  return true;
1271  }
1272  }
1273 ?>
setScenario($scenarioName)
static getUpdatedModels($modelClassName, $pageSize, $offset, $timestamp, $stateMetadataAdapterClassName=null, $owner=null)
static getUpdatedModelsCount($modelClassName, $timestamp, $stateMetadataAdapterClassName=null, $owner=null)
attemptToSaveModelFromData($model, $data, $redirectUrlParams=null, $redirect=true)
preAttemptToSaveModelFromDataHook(RedBeanModel $model, array &$data)
static getCreatedModelsCount($serviceName, $modelClassName, $timestamp, $stateMetadataAdapterClassName=null, $owner=null, $checkIfModelCreationApiSyncUtilIsNull=true)
manageModelRelations($model, $modelRelations)
static resolveAccessCanCurrentUserDeleteModel(RedBeanModel $model, $fromAjax=false)
static getModelToApiDataUtilData(RedBeanModel $model)
static resolveIncludingAdditionalData(Array &$data)
static getDeletedModelsCount($serviceName, $modelClassName, $timestamp, $stateMetadataAdapterClassName=null)
static makeWhere($modelClassName, array $metadata, &$joinTablesAdapter)
static resolveDynamicSearchClausesForModelIdsNeedingToBeItemIds($modelClassName, &$dynamicClauses)
getOffsetFromCurrentPageAndPageSize($currentPage, $pageSize)
static subValueSort($array, $subKey, $sortFunctionName)
Definition: ArrayUtil.php:153
static resolveAccessCanCurrentUserReadModel(RedBeanModel $model, $fromAjax=false)
makeRedBeanDataProviderByDataCollection($searchModel, $pageSize, $stateMetadataAdapterClassName=null, $dataCollection=null)
Definition: Controller.php:83
const MANY_MANY
Definition: BeanModel.php:78
static getDeletedModelIds($serviceName, $modelClassName, $pageSize, $offset, $timestamp, $stateMetadataAdapterClassName=null)
static getCreatedModels($serviceName, $modelClassName, $pageSize, $offset, $timestamp, $stateMetadataAdapterClassName=null, $owner=null, $checkIfModelCreationApiSyncUtilIsNull=true)
const HAS_MANY
Definition: BeanModel.php:71
static convertToBytes($value)
Definition: StringUtil.php:240
setModelScenarioFromData(RedBeanModel $model, array &$data)
static resolveAccessCanCurrentUserWriteModel(RedBeanModel $model, $fromAjax=false)
Generated on Thu Jul 9 2020 07:10:37
Account Suspended
Account Suspended
This Account has been suspended.
Contact your hosting provider for more information.