/**
  * @param string $nodeId
  * @param ModelRelationsAndAttributesToWorkflowAdapter $modelToWorkflowAdapter
  * @param RedBeanModel $precedingModel
  * @param string $precedingRelation
  */
 protected function resolvePrecedingModelRelationAndAdapterByNodeId($nodeId, &$modelToWorkflowAdapter, &$precedingModel, &$precedingRelation)
 {
     assert('$modelToWorkflowAdapter instanceof ModelRelationsAndAttributesToWorkflowAdapter');
     if ($nodeId == 'source') {
         return;
     }
     $relations = explode(FormModelUtil::RELATION_DELIMITER, $nodeId);
     $lastRelation = end($relations);
     foreach ($relations as $relation) {
         $relationModelClassName = $modelToWorkflowAdapter->getRelationModelClassName($relation);
         $precedingRelation = $relation;
         if ($relation != $lastRelation) {
             $precedingModel = new $relationModelClassName(false);
         } elseif (count($relations) == 1) {
             $precedingModel = $modelToWorkflowAdapter->getModel();
         }
         $modelToWorkflowAdapter = $this->makeModelRelationsAndAttributesToWorkflowAdapter($relationModelClassName::getModuleClassName(), $relationModelClassName);
     }
 }
 /**
  * @param string $relation
  * @param $model
  * @return array of models
  */
 public static function getInferredModelsByAtrributeAndModel($relation, $model)
 {
     assert('is_string($relation)');
     $realAttributeName = ModelRelationsAndAttributesToWorkflowAdapter::resolveRealAttributeName($relation);
     $relationModelClassName = ModelRelationsAndAttributesToWorkflowAdapter::getInferredRelationModelClassName($relation);
     $relatedModels = array();
     foreach ($model->{$realAttributeName} as $item) {
         try {
             $modelDerivationPathToItem = RuntimeUtil::getModelDerivationPathToItem($relationModelClassName);
             $relatedModels[] = $item->castDown(array($modelDerivationPathToItem));
         } catch (NotFoundException $e) {
         }
     }
     return $relatedModels;
 }
 protected static function resolveRelatedModelsForInferredRelations($attribute, $model, $relation, $resolvedAttributeModelClassName)
 {
     if (ModelRelationsAndAttributesToWorkflowAdapter::isAttributeInferred($attribute)) {
         $relatedModels = array();
         foreach ($model->{$relation} as $item) {
             if (get_class($item) == $resolvedAttributeModelClassName) {
                 $relatedModels[] = $item;
             } else {
                 try {
                     $modelDerivationPathToItem = RuntimeUtil::getModelDerivationPathToItem($resolvedAttributeModelClassName);
                     $relatedModels[] = $item->castDown(array($modelDerivationPathToItem));
                 } catch (NotFoundException $e) {
                 }
             }
         }
         return $relatedModels;
     } else {
         return $model->{$relation};
     }
 }
 /**
  * Notice the use of $modelToForgetCache. This was needed to avoid a caching issue with the following example.
  * If an opportunity fires, and a related account's opportunity is created. This new opportunity had a cached
  * model for account that was null.  So this is fixed by forgetting the new model after it is added to the account.
  * @throws FailedToSaveModelException
  * @throws NotSupportedException
  */
 protected function processCreateRelatedAction()
 {
     if ($this->action->relationFilter != ActionForWorkflowForm::RELATION_FILTER_ALL) {
         throw new NotSupportedException();
     }
     $modelClassName = get_class($this->triggeredModel);
     if ($this->triggeredModel->isADerivedRelationViaCastedUpModel($this->action->relation) && $this->triggeredModel->getDerivedRelationType($this->action->relation) == RedBeanModel::MANY_MANY) {
         foreach (WorkflowUtil::resolveDerivedModels($this->triggeredModel, $this->action->relation) as $relatedModel) {
             if ($this->resolveCreateModel($relatedModel, $this->action->relatedModelRelation)) {
                 $saved = $relatedModel->save();
                 if (!$saved) {
                     throw new FailedToSaveModelException();
                 }
             }
         }
     } elseif ($this->triggeredModel->getInferredRelationModelClassNamesForRelation(ModelRelationsAndAttributesToWorkflowAdapter::resolveRealAttributeName($this->action->relation)) != null) {
         foreach (WorkflowUtil::getInferredModelsByAtrributeAndModel($this->action->relation, $this->triggeredModel) as $relatedModel) {
             if ($this->resolveCreateModel($relatedModel, $this->action->relatedModelRelation)) {
                 $saved = $relatedModel->save();
                 if (!$saved) {
                     throw new FailedToSaveModelException();
                 }
             }
         }
     } elseif ($this->triggeredModel->{$this->action->relation} instanceof RedBeanMutableRelatedModels) {
         foreach ($this->triggeredModel->{$this->action->relation} as $relatedModel) {
             if ($this->resolveCreateModel($relatedModel, $this->action->relatedModelRelation)) {
                 $saved = $relatedModel->save();
                 if (!$saved) {
                     throw new FailedToSaveModelException();
                 }
             }
         }
     } elseif ($modelClassName::isRelationTypeAHasOneVariant($this->action->relation) && !$modelClassName::isOwnedRelation($this->action->relation)) {
         $relatedModel = $this->triggeredModel->{$this->action->relation};
         $modelToForgetCache = null;
         if ($this->resolveCreateModel($relatedModel, $this->action->relatedModelRelation, $modelToForgetCache)) {
             $saved = $relatedModel->save();
             if (!$saved) {
                 throw new FailedToSaveModelException();
             }
             if ($modelToForgetCache instanceof RedBeanModel) {
                 $modelToForgetCache->forget();
             }
         }
     } else {
         throw new NotSupportedException();
     }
 }
 /**
  * @param RedBeanModel $model
  * @param User $triggeredByUser
  * @return array
  * @throws NotSupportedException
  */
 public function makeRecipients(RedBeanModel $model, User $triggeredByUser)
 {
     $modelClassName = $this->modelClassName;
     $recipients = array();
     if ($model->isADerivedRelationViaCastedUpModel($this->relation) && $model->getDerivedRelationType($this->relation) == RedBeanModel::MANY_MANY) {
         foreach (WorkflowUtil::resolveDerivedModels($model, $this->relation) as $resolvedModel) {
             $recipients = self::resolveRecipientsAsUniquePeople($recipients, $this->resolveRecipients($resolvedModel));
         }
     } elseif ($modelClassName::getInferredRelationModelClassNamesForRelation(ModelRelationsAndAttributesToWorkflowAdapter::resolveRealAttributeName($this->relation)) != null) {
         foreach (WorkflowUtil::getInferredModelsByAtrributeAndModel($this->relation, $model) as $resolvedModel) {
             $recipients = self::resolveRecipientsAsUniquePeople($recipients, $this->resolveRecipients($resolvedModel));
         }
     } elseif ($model->{$this->relation} instanceof RedBeanMutableRelatedModels) {
         if (!$this->relationFilter == self::RELATION_FILTER_ALL) {
             throw new NotSupportedException();
         }
         foreach ($model->{$this->relation} as $resolvedModel) {
             $recipients = self::resolveRecipientsAsUniquePeople($recipients, $this->resolveRecipients($resolvedModel));
         }
     } elseif ($modelClassName::isRelationTypeAHasOneVariant($this->relation)) {
         if ($model->{$this->relation}->id > 0) {
             $recipients = $this->resolveRecipients($model->{$this->relation});
         }
     } else {
         throw new NotSupportedException();
     }
     return $recipients;
 }
 /**
  * @param string $methodToCall
  * @return array
  */
 protected function resolveActionAttributeFormsAndLabelsAndSortByMethod($methodToCall)
 {
     assert('$methodToCall == "getNonRequiredAttributesForActions" ||
                 $methodToCall == "getRequiredAttributesForActions" ||
                 $methodToCall == "getAllAttributesForActions"');
     $modelClassName = $this->getModelClassNameAndResolveForRelations();
     $attributeFormsIndexedByAttribute = array();
     $adapter = ModelRelationsAndAttributesToWorkflowAdapter::make($modelClassName::getModuleClassName(), $modelClassName, $this->_workflowType);
     foreach ($adapter->{$methodToCall}() as $attribute => $data) {
         if ($this->hasActionAttributeFormByName($attribute)) {
             $attributeFormsIndexedByAttribute[$attribute] = $this->getActionAttributeFormByName($attribute);
         } else {
             $attributeFormsIndexedByAttribute[$attribute] = $this->makeActionAttributeFormByAttribute($attribute);
         }
         if ($methodToCall == 'getRequiredAttributesForActions') {
             $attributeFormsIndexedByAttribute[$attribute]->shouldSetValue = true;
         }
         $additionalLabelContent = $this->resolveTooltipHelpContentByElementType($adapter->getModel(), $attribute);
         $attributeFormsIndexedByAttribute[$attribute]->setDisplayLabel($data['label'] . $additionalLabelContent);
     }
     $this->resolvePermissionsAttributeForm($modelClassName, $methodToCall, $attributeFormsIndexedByAttribute);
     return $attributeFormsIndexedByAttribute;
 }
 /**
  * @param array $attributeAndRelationData
  * @return string
  */
 protected function resolveRealAttributeNameForPenultimateRelation(array $attributeAndRelationData)
 {
     assert('count($this->attributeAndRelationData) > 0');
     array_pop($attributeAndRelationData);
     return ModelRelationsAndAttributesToWorkflowAdapter::resolveRealAttributeName(end($attributeAndRelationData));
 }
 /**
  * @depends testGetSelectableRelationsDataForEmailMessageRecipientModelRelation
  */
 public function testGetSelectableContactRelationsDataForEmailMessageRecipientModelRelation()
 {
     $model = new Account();
     $rules = new AccountsWorkflowRules();
     $workflow = new Workflow();
     $workflow->setType(Workflow::TYPE_ON_SAVE);
     $workflow->setModuleClassName('AccountsModule');
     $adapter = new ModelRelationsAndAttributesToWorkflowAdapter($model, $rules, $workflow->getType());
     $relations = $adapter->getSelectableContactRelationsDataForEmailMessageRecipientModelRelation();
     $this->assertEquals(1, count($relations));
     $this->assertTrue(isset($relations['contacts']));
     $model = new Contact();
     $rules = new ContactsWorkflowRules();
     $workflow = new Workflow();
     $workflow->setType(Workflow::TYPE_ON_SAVE);
     $workflow->setModuleClassName('ContactsModule');
     $adapter = new ModelRelationsAndAttributesToWorkflowAdapter($model, $rules, $workflow->getType());
     $relations = $adapter->getSelectableContactRelationsDataForEmailMessageRecipientModelRelation();
     $this->assertEquals(0, count($relations));
     $model = new Task();
     $rules = new TasksWorkflowRules();
     $workflow = new Workflow();
     $workflow->setType(Workflow::TYPE_ON_SAVE);
     $workflow->setModuleClassName('TasksModule');
     $adapter = new ModelRelationsAndAttributesToWorkflowAdapter($model, $rules, $workflow->getType());
     $relations = $adapter->getSelectableContactRelationsDataForEmailMessageRecipientModelRelation();
     $this->assertEquals(1, count($relations));
     $this->assertTrue(isset($relations['Contact__activityItems__Inferred']));
 }
 /**
  * @return string
  * @throws NotSupportedException
  */
 protected function resolveModelClassName()
 {
     $modelClassName = $this->modelClassName;
     if ($this->relation == null) {
         return $modelClassName;
     }
     if ($modelClassName::isADerivedRelationViaCastedUpModel($this->relation) && $modelClassName::getDerivedRelationType($this->relation) == RedBeanModel::MANY_MANY) {
         return $modelClassName::getDerivedRelationModelClassName($this->relation);
     } elseif ($modelClassName::getInferredRelationModelClassNamesForRelation(ModelRelationsAndAttributesToWorkflowAdapter::resolveRealAttributeName($this->relation)) != null) {
         return ModelRelationsAndAttributesToWorkflowAdapter::getInferredRelationModelClassName($this->relation);
     } elseif ($modelClassName::isRelationTypeAHasManyVariant($this->relation) || $modelClassName::isRelationTypeAHasOneVariant($this->relation)) {
         return $modelClassName::getRelationModelClassName($this->relation);
     } else {
         throw new NotSupportedException();
     }
 }