All Data Structures Functions Variables Pages
ModelRelationsAndAttributesToWorkflowAdapter.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 
41  {
42  const DYNAMIC_ATTRIBUTE_USER = 'User';
43 
44  const DYNAMIC_RELATION_INFERRED = 'Inferred';
45 
49  private static $adaptersByModelClassNameAndType;
50 
54  protected $model;
55 
59  protected $rules;
60 
64  protected $workflowType;
65 
69  protected $moduleClassName;
70 
75  private $derivedAttributesData;
76 
84  public static function make($moduleClassName, $modelClassName, $workflowType)
85  {
86  assert('is_string($moduleClassName)');
87  assert('is_string($modelClassName)');
88  assert('is_string($workflowType)');
89  if (!isset(self::$adaptersByModelClassNameAndType[$modelClassName . $workflowType]))
90  {
91  $rules = WorkflowRules::makeByModuleClassName($moduleClassName);
92  $model = new $modelClassName(false);
93  if ($workflowType == Workflow::TYPE_ON_SAVE)
94  {
95  $adapter = new ModelRelationsAndAttributesToOnSaveWorkflowAdapter($model, $rules,
96  $workflowType, $moduleClassName);
97  }
98  elseif ($workflowType == Workflow::TYPE_BY_TIME)
99  {
100  $adapter = new ModelRelationsAndAttributesToByTimeWorkflowAdapter($model, $rules,
101  $workflowType, $moduleClassName);
102  }
103  else
104  {
105  throw new NotSupportedException();
106  }
107  self::$adaptersByModelClassNameAndType[$modelClassName . $workflowType] = $adapter;
108  }
109  return self::$adaptersByModelClassNameAndType[$modelClassName . $workflowType];
110  }
111 
115  public function getModel()
116  {
117  return $this->model;
118  }
119 
123  public function getModelClassName()
124  {
125  return get_class($this->model);
126  }
127 
131  public function getRules()
132  {
133  return $this->rules;
134  }
135 
144  public function __construct(RedBeanModel $model, WorkflowRules $rules, $workflowType, $moduleClassName = null)
145  {
146  assert('is_string($workflowType)');
147  assert('is_string($moduleClassName) || $moduleClassName == null');
148  $this->model = $model;
149  $this->rules = $rules;
150  $this->workflowType = $workflowType;
151  if ($moduleClassName == null)
152  {
153  $moduleClassName = $model::getModuleClassName();
154  }
155  $this->moduleClassName = $moduleClassName;
156  }
157 
163  public function getAttributeLabel($attribute)
164  {
165  assert('is_string($attribute)');
166  if ($this->isDynamicallyDerivedAttribute($attribute))
167  {
168  $resolvedAttribute = $attribute;
169  }
170  else
171  {
172  $resolvedAttribute = static::resolveRealAttributeName($attribute);
173  }
174  $attributesData = $this->getAttributesIncludingDerivedAttributesData();
175  if (!isset($attributesData[$resolvedAttribute]))
176  {
177  throw new NotSupportedException('Label not found for: ' . $resolvedAttribute . ' from ' . $attribute);
178  }
179  return $attributesData[$resolvedAttribute]['label'];
180  }
181 
187  public function getRelationLabel($relation)
188  {
189  assert('is_string($relation)');
190  $relationsData = $this->getSelectableRelationsData();
191  if (!isset($relationsData[$relation]))
192  {
193  throw new NotSupportedException();
194  }
195  return $relationsData[$relation]['label'];
196  }
197 
204  public function isUsedAsARelation($relationOrAttribute)
205  {
206  assert('is_string($relationOrAttribute)');
207  $relations = $this->getSelectableRelationsData();
208  if (isset($relations[$relationOrAttribute]))
209  {
210  return true;
211  }
212  else
213  {
214  return false;
215  }
216  }
217 
223  public function getRelationModuleClassName($relation)
224  {
225  assert('is_string($relation)');
226  $delimiter = FormModelUtil::DELIMITER;
227  $relationAndInferredData = explode($delimiter, $relation);
228  $derivedRelations = $this->getDerivedRelationsViaCastedUpModelData();
229  if (count($relationAndInferredData) == 3)
230  {
231  list($modelClassName, $notUsed, $notUsed2) = $relationAndInferredData;
232  return $modelClassName::getModuleClassName();
233  }
234  elseif (count($relationAndInferredData) == 1 && isset($derivedRelations[$relation]))
235  {
236  $modelClassName = $this->model->getDerivedRelationModelClassName($relation);
237  return $modelClassName::getModuleClassName();
238  }
239  elseif (count($relationAndInferredData) == 1)
240  {
241  $modelClassName = $this->model->getRelationModelClassName($relation);
242  return $modelClassName::getModuleClassName();
243  }
244  else
245  {
246  throw new NotSupportedException();
247  }
248  }
249 
255  public function getRelationModelClassName($relation)
256  {
257  assert('is_string($relation)');
258  if (null !== $relationModelClassName = self::getInferredRelationModelClassName($relation))
259  {
260  return $relationModelClassName;
261  }
262  $delimiter = FormModelUtil::DELIMITER;
263  $relationAndInferredData = explode($delimiter, $relation);
264  $derivedRelations = $this->getDerivedRelationsViaCastedUpModelData();
265  if (count($relationAndInferredData) == 1 && isset($derivedRelations[$relation]))
266  {
267  return $this->model->getDerivedRelationModelClassName($relation);
268  }
269  elseif (count($relationAndInferredData) == 1)
270  {
271  return $this->model->getRelationModelClassName($relation);
272  }
273  else
274  {
275  throw new NotSupportedException();
276  }
277  }
278 
283  public static function getInferredRelationModelClassName($relation)
284  {
285  assert('is_string($relation)');
286  $delimiter = FormModelUtil::DELIMITER;
287  $relationAndInferredData = explode($delimiter, $relation);
288  if (count($relationAndInferredData) == 3)
289  {
290  list($modelClassName, $notUsed, $notUsed2) = $relationAndInferredData;
291  return $modelClassName;
292  }
293  }
294 
298  public function getAttributesForTriggers()
299  {
300  $attributes = $this->getAttributesNotIncludingDerivedAttributesData();
301  $attributes = array_merge($attributes, $this->getDynamicallyDerivedAttributesData());
302  $sortedAttributes = ArrayUtil::subValueSort($attributes, 'label', 'asort');
303  return $sortedAttributes;
304  }
305 
309  public function getAttributesForTimeTrigger()
310  {
311  throw new NotImplementedException();
312  }
313 
318  public function getAllAttributesForActions()
319  {
320  $attributes = $this->resolveAttributesForActionsOrTimeTriggerData(true, true);
321  $attributes = array_merge($attributes,
323  $sortedAttributes = ArrayUtil::subValueSort($attributes, 'label', 'asort');
324  return $sortedAttributes;
325  }
326 
331  {
332  $attributes = $this->resolveAttributesForActionsOrTimeTriggerData(true);
333  $attributes = array_merge($attributes,
335  $sortedAttributes = ArrayUtil::subValueSort($attributes, 'label', 'asort');
336  return $sortedAttributes;
337  }
338 
343  {
344  $attributes = $this->resolveAttributesForActionsOrTimeTriggerData(false, true);
345  $attributes = array_merge($attributes,
347  $sortedAttributes = ArrayUtil::subValueSort($attributes, 'label', 'asort');
348  return $sortedAttributes;
349  }
350 
356  public function getAvailableOperatorsType($attribute)
357  {
358  assert('is_string($attribute)');
359  //Currently only User is supported as a dynamically derived attributed
360  if ($this->isDynamicallyDerivedAttribute($attribute))
361  {
362  return ModelAttributeToOperatorTypeUtil::AVAILABLE_OPERATORS_TYPE_HAS_ONE;
363  }
364  if ($this->isDerivedAttribute($attribute))
365  {
366  throw new NotSupportedException();
367  }
368  $resolvedAttribute = static::resolveRealAttributeName($attribute);
369  if (null != $availableOperatorsTypeFromRule = $this->rules->getAvailableOperatorsTypes($this->model,
370  $resolvedAttribute))
371  {
372  return $availableOperatorsTypeFromRule;
373  }
374  return ModelAttributeToWorkflowOperatorTypeUtil::getAvailableOperatorsType($this->model, $resolvedAttribute);
375  }
376 
383  public function getTriggerValueElementType($attribute)
384  {
385  assert('is_string($attribute)');
386  if ($this->isDerivedAttribute($attribute))
387  {
388  return null;
389  }
390  if ($this->isDynamicallyDerivedAttribute($attribute))
391  {
392  $parts = explode(FormModelUtil::DELIMITER, $attribute);
393  if ($parts[1] != 'User')
394  {
395  throw new NotSupportedException();
396  }
397  return 'UserNameId';
398  }
399  $resolvedAttribute = static::resolveRealAttributeName($attribute);
400  if (null != $triggerValueElementTypeFromRule = $this->rules->getTriggerValueElementType($this->model,
401  $resolvedAttribute))
402  {
403  return $triggerValueElementTypeFromRule;
404  }
405  return ModeAttributeToWorkflowTriggerValueElementTypeUtil::getType($this->model, $resolvedAttribute);
406  }
407 
414  public function getDisplayElementType($attribute)
415  {
416  assert('is_string($attribute)');
417  $derivedAttributes = $this->getDerivedAttributesData();
418  if (isset($derivedAttributes[$attribute]))
419  {
420  return $derivedAttributes[$attribute]['derivedAttributeType'];
421  }
422  if ($this->isDynamicallyDerivedAttribute($attribute))
423  {
424  $parts = explode(FormModelUtil::DELIMITER, $attribute);
425  if ($parts[1] != 'User')
426  {
427  throw new NotSupportedException();
428  }
429  return 'User';
430  }
431  $resolvedAttribute = static::resolveRealAttributeName($attribute);
432  return $this->getRealModelAttributeType($resolvedAttribute);
433  }
434 
439  public function getRealModelAttributeType($attribute)
440  {
441  assert('is_string($attribute)');
442  return ModelAttributeToMixedTypeUtil::getType($this->model, $attribute);
443  }
444 
448  public function getAllRelationsData()
449  {
450  $attributes = array();
451  foreach ($this->model->getAttributes() as $attribute => $notUsed)
452  {
453  if ($this->model->isRelation($attribute))
454  {
455  $attributes[$attribute] = array('label' => $this->model->getAttributeLabel($attribute));
456  }
457  }
458  return $attributes;
459  }
460 
469  public function getSelectableRelationsDataResolvedForUserAccess(User $user, Array $relations)
470  {
471  assert('$user->id > 0');
472  foreach ($relations as $relation => $data)
473  {
474  if (null != $moduleClassName = $this->getRelationModuleClassName($relation))
475  {
476  if ($moduleClassName != 'UsersModule' && !RightsUtil::canUserAccessModule($moduleClassName , $user))
477  {
478  unset($relations[$relation]);
479  }
480  }
481  else
482  {
483  throw new NotSupportedException();
484  }
485  }
486  return $relations;
487  }
488 
500  public function getSelectableRelationsData(RedBeanModel $precedingModel = null, $precedingRelation = null)
501  {
502  if (($precedingModel != null && $precedingRelation == null) ||
503  ($precedingModel == null && $precedingRelation != null))
504  {
505  throw new NotSupportedException();
506  }
507  $attributes = array();
508  foreach ($this->model->getAttributes() as $attribute => $notUsed)
509  {
510  if ($this->model->isRelation($attribute) &&
511  !$this->rules->relationIsUsedAsAttribute($this->model, $attribute) &&
512  $this->rules->attributeCanBeTriggered($this->model, $attribute) &&
513  !$this->relationLinksToPrecedingRelation($attribute, $precedingModel, $precedingRelation)
514  )
515  {
516  $this->resolveRelationToSelectableRelationData($attributes, $attribute);
517  }
518  }
519  $attributes = array_merge($attributes, $this->getDerivedRelationsViaCastedUpModelData($precedingModel, $precedingRelation));
520  $attributes = array_merge($attributes, $this->getInferredRelationsData($precedingModel, $precedingRelation));
521  $sortedAttributes = ArrayUtil::subValueSort($attributes, 'label', 'asort');
522  return $sortedAttributes;
523  }
524 
529  {
530  $attributes = array('id' => array('label' => Zurmo::t('Core', 'Id')));
531  $attributes = array_merge($attributes, $this->getAttributesNotIncludingDerivedAttributesData());
532  $attributes = array_merge($attributes, $this->getDerivedAttributesData());
533  $attributes = array_merge($attributes, $this->getDynamicallyDerivedAttributesData());
534  return $attributes;
535  }
536 
542  public function isRelationASingularRelation($relation)
543  {
544  assert('is_string($relation)');
545  $delimiter = FormModelUtil::DELIMITER;
546  $relationAndInferredData = explode($delimiter, $relation);
547  $derivedRelations = $this->getDerivedRelationsViaCastedUpModelData();
548  if (count($relationAndInferredData) == 3)
549  {
550  list($modelClassName, $relation, $notUsed) = $relationAndInferredData;
551  $type = $this->model->getRelationType($relation);
552  }
553  elseif (count($relationAndInferredData) == 2)
554  {
555  list($relation, $notUsed) = $relationAndInferredData;
556  $type = $this->model->getRelationType($relation);
557  }
558  elseif (count($relationAndInferredData) == 1 && isset($derivedRelations[$relation]))
559  {
560  $type = $this->model->getDerivedRelationType($relation);
561  }
562  elseif (count($relationAndInferredData) == 1)
563  {
564  $type = $this->model->getRelationType($relation);
565  }
566  else
567  {
568  throw new NotSupportedException();
569  }
570  if ( $type == RedBeanModel::HAS_ONE ||
573  {
574  return true;
575  }
576  return false;
577  }
578 
587  public function getInferredRelationsData(RedBeanModel $precedingModel = null, $precedingRelation = null,
588  $onlyIncludeThisModelClassName = null)
589  {
590  if (($precedingModel != null && $precedingRelation == null) ||
591  ($precedingModel == null && $precedingRelation != null))
592  {
593  throw new NotSupportedException();
594  }
595  $attributes = array();
596  foreach ($this->model->getAttributes() as $attribute => $notUsed)
597  {
598  $inferredRelationModelClassNames = $this->getInferredRelationModelClassNamesForRelation($attribute);
599  if ($this->model->isRelation($attribute) && $inferredRelationModelClassNames != null)
600  {
601  foreach ($inferredRelationModelClassNames as $modelClassName)
602  {
603  if ($onlyIncludeThisModelClassName === null || $onlyIncludeThisModelClassName == $modelClassName)
604  {
605  if (!$this->inferredRelationLinksToPrecedingRelation($modelClassName,
606  $attribute, $precedingModel, $precedingRelation))
607  {
608  $attributes[$modelClassName . FormModelUtil::DELIMITER .
609  $attribute . FormModelUtil::DELIMITER . self::DYNAMIC_RELATION_INFERRED] =
610  array('label' => $modelClassName::getModelLabelByTypeAndLanguage('Plural'));
611  }
612  }
613  }
614  }
615  }
616  return $attributes;
617  }
618 
624  public function getTriggerRulesByAttribute($attribute, $ruleAttributeName)
625  {
626  assert('is_string($attribute)');
627  assert('is_string($ruleAttributeName)');
628  $rules = array();
629  $dynamicallyDerivedAttributes = $this->getDynamicallyDerivedAttributesData();
630  if ($this->model->isAttribute($attribute) && $this->model->{$attribute} instanceof CurrencyValue)
631  {
632  $rules[] = array($ruleAttributeName, 'type', 'type' => 'float');
633  }
634  elseif (in_array($attribute, $dynamicallyDerivedAttributes))
635  {
636  $rules[] = array($ruleAttributeName, 'type' => 'string');
637  }
638  elseif ($this->model->isAttribute($attribute))
639  {
642  get_class($this->model),
643  $attribute,
644  $ruleAttributeName,
645  false,
646  true,
647  false);
648  }
649  return $rules;
650  }
651 
656  public function relationIsUsedAsAttribute($relation)
657  {
658  assert('is_string($relation)');
659  if ($this->model->isAttribute($relation) && $this->isUsedAsARelation($relation))
660  {
661  return false;
662  }
663  if ($this->model->isAttribute($relation) && !$this->model->isRelation($relation))
664  {
665  return false;
666  }
667  if ($this->isDerivedAttribute($relation))
668  {
669  return false;
670  }
671  return $this->rules->relationIsUsedAsAttribute($this->model, $relation);
672  }
673 
679  {
680  assert('is_string($relation)');
681  $relationsData = $this->getDerivedRelationsViaCastedUpModelData();
682  if (isset($relationsData[$relation]))
683  {
684  return true;
685  }
686  return false;
687  }
688 
693  public function isInferredRelation($relation)
694  {
695  assert('is_string($relation)');
696  $relationsData = $this->getInferredRelationsData();
697  if (isset($relationsData[$relation]))
698  {
699  return true;
700  }
701  return false;
702  }
703 
708  public function isDynamicallyDerivedAttribute($attribute)
709  {
710  assert('is_string($attribute)');
711  $dynamicallyDerivedAttributes = $this->getDynamicallyDerivedAttributesData();
712  if (isset($dynamicallyDerivedAttributes[$attribute]))
713  {
714  return true;
715  }
716  return false;
717  }
718 
723  public function isAttributeReadOptimization($attribute)
724  {
725  assert('is_string($attribute)');
726  if ($attribute == 'ReadOptimization')
727  {
728  return true;
729  }
730  return false;
731  }
732 
737  public function isDerivedAttribute($attribute)
738  {
739  assert('is_string($attribute)');
740  $derivedAttributes = $this->getDerivedAttributesData();
741  if (isset($derivedAttributes[$attribute]))
742  {
743  return true;
744  }
745  return false;
746  }
747 
752  public static function resolveRealAttributeName($attribute)
753  {
754  assert('is_string($attribute)');
755  $delimiter = FormModelUtil::DELIMITER;
756  $attributeAndInferredData = explode($delimiter, $attribute);
757  if (count($attributeAndInferredData) == 3)
758  {
759  list($modelClassName, $attribute, $notUsed) = $attributeAndInferredData;
760  return $attribute;
761  }
762  elseif (count($attributeAndInferredData) == 2)
763  {
764  list($attribute, $notUsed) = $attributeAndInferredData;
765  return $attribute;
766  }
767  else
768  {
769  return $attribute;
770  }
771  }
772 
779  public static function isAttributeInferred($attribute)
780  {
781  assert('is_string($attribute)');
782  $delimiter = FormModelUtil::DELIMITER;
783  $attributeAndInferredData = explode($delimiter, $attribute);
784  if (count($attributeAndInferredData) == 3)
785  {
786  return true;
787  }
788  return false;
789  }
790 
797  public function getSelectableRelationsDataForTriggers(RedBeanModel $precedingModel = null, $precedingRelation = null)
798  {
799  if (($precedingModel != null && $precedingRelation == null) ||
800  ($precedingModel == null && $precedingRelation != null))
801  {
802  throw new NotSupportedException();
803  }
804  $onlyIncludeOwnedRelations = false;
805  if (($precedingModel != null && $precedingRelation != null))
806  {
807  $onlyIncludeOwnedRelations = true;
808  }
809  $attributes = array();
810  foreach ($this->model->getAttributes() as $attribute => $notUsed)
811  {
812  if ($this->model->isRelation($attribute) &&
813  !$this->rules->relationIsUsedAsAttribute($this->model, $attribute) &&
814  $this->rules->attributeCanBeTriggered($this->model, $attribute) &&
815  !$this->relationLinksToPrecedingRelation($attribute, $precedingModel, $precedingRelation) &&
816  (!$onlyIncludeOwnedRelations ||
817  ($onlyIncludeOwnedRelations && $this->model->isOwnedRelation($attribute)))
818  )
819  {
820  $this->resolveRelationToSelectableRelationData($attributes, $attribute);
821  }
822  }
823  if (!$onlyIncludeOwnedRelations)
824  {
825  //Currently this is not handled correctly in WorkflowTriggersUtil::isTriggerTrueByModel so we disable it.
826  //TODO: Refactor WorkflowTriggersUtil to handle this kind of triggers properly.
827  //$attributes = array_merge($attributes, $this->getDerivedRelationsViaCastedUpModelData($precedingModel, $precedingRelation));
828  $attributes = array_merge($attributes, $this->getInferredRelationsData($precedingModel, $precedingRelation));
829  }
830  $sortedAttributes = ArrayUtil::subValueSort($attributes, 'label', 'asort');
831  return $sortedAttributes;
832  }
833 
840  {
841  return $this->getSelectableRelationsDataForActionTypeRelation();
842  }
843 
850  {
851  $attributes = array();
852  foreach ($this->model->getAttributes() as $attribute => $notUsed)
853  {
854  if ($this->model->isRelation($attribute) &&
855  !$this->rules->relationIsUsedAsAttribute($this->model, $attribute) &&
856  $this->rules->attributeCanBeTriggered($this->model, $attribute) &&
857  !$this->model->isOwnedRelation($attribute) &&
858  $this->model->getRelationModelClassName($attribute) == 'Contact')
859  {
860  $this->resolveRelationToSelectableRelationData($attributes, $attribute);
861  }
862  }
863  $attributes = array_merge($attributes, $this->getDerivedRelationsViaCastedUpModelData(null, null, 'Contact'));
864  $attributes = array_merge($attributes, $this->getInferredRelationsData(null, null, 'Contact'));
865  $sortedAttributes = ArrayUtil::subValueSort($attributes, 'label', 'asort');
866  return $sortedAttributes;
867  }
868 
874  {
875  $attributes = array();
876  foreach ($this->model->getAttributes() as $attribute => $notUsed)
877  {
878  if ($this->model->isRelation($attribute) &&
879  !$this->rules->relationIsUsedAsAttribute($this->model, $attribute) &&
880  $this->rules->attributeCanBeTriggered($this->model, $attribute) &&
881  !$this->model->isOwnedRelation($attribute) &&
882  $this->model->getRelationModelClassName($attribute) != 'User')
883  {
884  $this->resolveRelationToSelectableRelationData($attributes, $attribute);
885  }
886  }
887  $attributes = array_merge($attributes, $this->getDerivedRelationsViaCastedUpModelData());
888  $attributes = array_merge($attributes, $this->getInferredRelationsData());
889  $sortedAttributes = ArrayUtil::subValueSort($attributes, 'label', 'asort');
890  return $sortedAttributes;
891  }
892 
897  {
898  $attributes = array();
899  foreach ($this->model->getAttributes() as $attribute => $notUsed)
900  {
901  if ((($this->model->isRelation($attribute) &&
902  $this->rules->relationIsUsedAsAttribute($this->model, $attribute)) ||
903  !$this->model->isRelation($attribute) &&
904  $this->rules->attributeCanBeTriggered($this->model, $attribute)))
905  {
906  $attributes[$attribute] = array('label' => $this->model->getAttributeLabel($attribute));
907  }
908  }
909  return $attributes;
910  }
911 
918  protected function resolveAttributesForActionsOrTimeTriggerData($includeRequired = false,
919  $includeNonRequired = false,
920  $includeReadOnly = false)
921 
922  {
923  assert('is_bool($includeRequired)');
924  assert('is_bool($includeNonRequired)');
925  assert('is_bool($includeReadOnly)');
926  $attributes = array();
927  foreach ($this->model->getAttributes() as $attribute => $notUsed)
928  {
929  if ((!$this->model->isAttributeReadOnly($attribute) || $includeReadOnly) &&
930  (($this->model->isRelation($attribute) &&
931  $this->rules->relationIsUsedAsAttribute($this->model, $attribute)) ||
932  !$this->model->isRelation($attribute) &&
933  $this->rules->attributeCanBeTriggered($this->model, $attribute)))
934  {
935  $attributeIsRequired = $this->model->isAttributeRequired($attribute);
936  if (($includeNonRequired && !$attributeIsRequired) ||
937  ($includeRequired && $attributeIsRequired))
938  {
939  $attributes[$attribute] = array('label' => $this->model->getAttributeLabel($attribute));
940  }
941  }
942  }
943  return $attributes;
944  }
945 
953  protected function derivedRelationLinksToPrecedingRelation($relationModelClassName, $opposingRelation,
954  RedBeanModel $precedingModel = null,
955  $precedingRelation = null)
956  {
957  assert('is_string($relationModelClassName)');
958  assert('is_string($opposingRelation)');
959  if ($precedingModel == null || $precedingRelation == null)
960  {
961  return false;
962  }
963  if ($relationModelClassName == get_class($precedingModel) && $opposingRelation == $precedingRelation)
964  {
965  return true;
966  }
967  return false;
968  }
969 
977  protected function inferredRelationLinksToPrecedingRelation($inferredModelClassName, $relation,
978  RedBeanModel $precedingModel = null,
979  $precedingRelation = null)
980  {
981  assert('is_string($inferredModelClassName)');
982  assert('is_string($relation)');
983  if ($precedingModel == null || $precedingRelation == null)
984  {
985  return false;
986  }
987  if ($inferredModelClassName != get_class($precedingModel))
988  {
989  return false;
990  }
991  if ($precedingModel->isADerivedRelationViaCastedUpModel($precedingRelation) &&
992  $precedingModel->getDerivedRelationViaCastedUpModelOpposingRelationName($precedingRelation) == $relation)
993  {
994  return true;
995  }
996  return false;
997  }
998 
1005  protected function relationLinksToPrecedingRelation($relation, RedBeanModel $precedingModel = null,
1006  $precedingRelation = null)
1007  {
1008  return RedBeanModel::relationLinksToPrecedingRelation(get_class($this->model), $relation,
1009  get_class($precedingModel), $precedingRelation);
1010  }
1011 
1020  protected function getDerivedRelationsViaCastedUpModelData(RedBeanModel $precedingModel = null, $precedingRelation = null,
1021  $onlyIncludeThisModelClassName = null)
1022  {
1023  assert('$onlyIncludeThisModelClassName === null || is_string($onlyIncludeThisModelClassName)');
1024  if (($precedingModel != null && $precedingRelation == null) ||
1025  ($precedingModel == null && $precedingRelation != null))
1026  {
1027  throw new NotSupportedException();
1028  }
1029  $attributes = array();
1030  $metadata = $this->model->getMetadata();
1031  foreach ($metadata as $modelClassName => $modelClassMetadata)
1032  {
1033  if (isset($metadata[$modelClassName]["derivedRelationsViaCastedUpModel"]))
1034  {
1035  foreach ($metadata[$modelClassName]["derivedRelationsViaCastedUpModel"] as $relation => $derivedRelationData)
1036  {
1037  $relationModelClassName = $this->model->getDerivedRelationModelClassName($relation);
1038  if ($onlyIncludeThisModelClassName === null || $relationModelClassName == $onlyIncludeThisModelClassName)
1039  {
1040  if (!$this->derivedRelationLinksToPrecedingRelation(
1041  $relationModelClassName,
1042  $this->model->getDerivedRelationViaCastedUpModelOpposingRelationName($relation),
1043  $precedingModel,
1044  $precedingRelation))
1045  {
1046  $attributes[$relation] = array('label' => $this->model->getAttributeLabel($relation));
1047  }
1048  }
1049  }
1050  }
1051  }
1052  return $attributes;
1053  }
1054 
1058  protected function getDerivedAttributesData()
1059  {
1060  if ($this->derivedAttributesData == null)
1061  {
1062  $attributes = array();
1063  $calculatedAttributes = CalculatedDerivedAttributeMetadata::getAllByModelClassName(get_class($this->model));
1064  foreach ($calculatedAttributes as $attribute)
1065  {
1066  $attributes[$attribute->name] = array('label' => $attribute->getLabelByLanguage(Yii::app()->language),
1067  'derivedAttributeType' => 'CalculatedNumber');
1068  }
1069  $this->derivedAttributesData = array_merge($attributes, $this->rules->getDerivedAttributeTypesData($this->model));
1070  }
1071  return $this->derivedAttributesData;
1072  }
1073 
1078  {
1079  $attributes = array();
1080  foreach ($this->model->getAttributes() as $attribute => $notUsed)
1081  {
1082  if (!$this->model instanceof User &&
1083  $this->model->isRelation($attribute) &&
1084  $this->model->getRelationModelClassName($attribute) == 'User')
1085  {
1086  $attributes[$attribute . FormModelUtil::DELIMITER . self::DYNAMIC_ATTRIBUTE_USER] =
1087  array('label' => $this->model->getAttributeLabel($attribute));
1088  }
1089  }
1090  return $attributes;
1091  }
1092 
1099  protected function resolveDynamicallyDerivedAttributesForActionsOrTimeTriggerData($includeRequired = false,
1100  $includeNonRequired = false,
1101  $includeReadOnly = false)
1102 
1103  {
1104  assert('is_bool($includeRequired)');
1105  assert('is_bool($includeNonRequired)');
1106  assert('is_bool($includeReadOnly)');
1107  $attributes = array();
1108  foreach ($this->model->getAttributes() as $attribute => $notUsed)
1109  {
1110  if (!$this->model instanceof User &&
1111  $this->model->isRelation($attribute) &&
1112  (!$this->model->isAttributeReadOnly($attribute) || $includeReadOnly) &&
1113  $this->model->getRelationModelClassName($attribute) == 'User')
1114  {
1115  $attributeIsRequired = $this->model->isAttributeRequired($attribute);
1116  if (($includeNonRequired && !$attributeIsRequired) ||
1117  ($includeRequired && $attributeIsRequired))
1118  {
1119  $attributes[$attribute . FormModelUtil::DELIMITER . self::DYNAMIC_ATTRIBUTE_USER] =
1120  array('label' => $this->model->getAttributeLabel($attribute));
1121  }
1122  }
1123  if ($this->model->isRelation($attribute) && $this->model->isOwnedRelation($attribute) &&
1124  $this->isRelationASingularRelation($attribute) &&
1125  ($this->model->getRelationModelClassName($attribute) == 'Address' ||
1126  $this->model->getRelationModelClassName($attribute) == 'Email'))
1127  {
1128  $relatedModel = $this->model->$attribute;
1129  //Assumes only Email or Address are possible owned models here
1130  $zurmoRules = WorkflowRules::makeByModuleClassName('ZurmoModule');
1131  foreach ($relatedModel->getAttributes() as $relatedAttribute => $notUsed)
1132  {
1133  if (!$relatedModel->isAttributeReadOnly($relatedAttribute) &&
1134  !$relatedModel->isRelation($relatedAttribute) &&
1135  $zurmoRules->attributeCanBeTriggered($relatedModel, $relatedAttribute))
1136  {
1137  $relatedAttributeIsRequired = $relatedModel->isAttributeRequired($relatedAttribute);
1138  if (($includeNonRequired && !$relatedAttributeIsRequired) ||
1139  ($includeRequired && $relatedAttributeIsRequired))
1140  {
1141  $attributes[$attribute . FormModelUtil::RELATION_DELIMITER . $relatedAttribute] =
1142  array('label' => $this->model->getAttributeLabel($attribute)
1144  . ' ' . $relatedModel->getAttributeLabel($relatedAttribute));
1145  }
1146  }
1147  }
1148  }
1149  }
1150  return $attributes;
1151  }
1152 
1158  {
1159  assert('is_string($relation)');
1160  return $this->model->getInferredRelationModelClassNamesForRelation($relation);
1161  }
1162 
1167  protected function resolveRelationToSelectableRelationData(& $attributes, $attribute)
1168  {
1169  assert('is_array($attributes)');
1170  assert('is_string($attribute)');
1171  $attributes[$attribute] = array('label' => $this->model->getAttributeLabel($attribute));
1172  }
1173  }
1174 ?>
getSelectableRelationsData(RedBeanModel $precedingModel=null, $precedingRelation=null)
inferredRelationLinksToPrecedingRelation($inferredModelClassName, $relation, RedBeanModel $precedingModel=null, $precedingRelation=null)
getInferredRelationsData(RedBeanModel $precedingModel=null, $precedingRelation=null, $onlyIncludeThisModelClassName=null)
resolveDynamicallyDerivedAttributesForActionsOrTimeTriggerData($includeRequired=false, $includeNonRequired=false, $includeReadOnly=false)
Definition: User.php:37
getSelectableRelationsDataForTriggers(RedBeanModel $precedingModel=null, $precedingRelation=null)
__construct(RedBeanModel $model, WorkflowRules $rules, $workflowType, $moduleClassName=null)
const HAS_ONE
Definition: BeanModel.php:64
const HAS_ONE_BELONGS_TO
Definition: BeanModel.php:48
static getApplicableRulesByModelClassNameAndAttributeName($modelClassName, $attributeName, $ruleAttributeName, $requiredRuleIsApplicable=false, $treatDateTimeAsDate=false, $readOnlyRuleIsApplicable=true)
relationLinksToPrecedingRelation($relation, RedBeanModel $precedingModel=null, $precedingRelation=null)
resolveAttributesForActionsOrTimeTriggerData($includeRequired=false, $includeNonRequired=false, $includeReadOnly=false)
const RELATION_DELIMITER
static subValueSort($array, $subKey, $sortFunctionName)
Definition: ArrayUtil.php:153
static make($moduleClassName, $modelClassName, $workflowType)
derivedRelationLinksToPrecedingRelation($relationModelClassName, $opposingRelation, RedBeanModel $precedingModel=null, $precedingRelation=null)
static canUserAccessModule($moduleClassName, $user)
Definition: RightsUtil.php:103
getDerivedRelationsViaCastedUpModelData(RedBeanModel $precedingModel=null, $precedingRelation=null, $onlyIncludeThisModelClassName=null)
static makeByModuleClassName($moduleClassName)
const HAS_MANY_BELONGS_TO
Definition: BeanModel.php:58
static relationLinksToPrecedingRelation($modelClassName, $relation, $precedingModelClassName=null, $precedingRelation=null)
static isRelation($attributeName)
Definition: BeanModel.php:220
static getType($model, $attributeName)
static getAllByModelClassName($modelClassName)
Generated on Fri Jun 5 2020 07:10:35