Beispiel #1
0
 /**
  * Create a new record from the parent Model and new related records with it.
  *
  * @param  array  $attributes
  * @param  array  $relations
  * @return \Vinelab\NeoEloquent\Eloquent\Model
  */
 public function createWith(array $attributes, array $relations)
 {
     // Collect the model attributes and label in the form of ['label' => $label, 'attributes' => $attributes]
     // as expected by the Query Builder.
     $attributes = $this->prepareForCreation($this->model, $attributes);
     $model = ['label' => $this->model->getTable(), 'attributes' => $attributes];
     /**
      * Collect the related models in the following for as expected by the Query Builder:
      *
      *  [
      *       'label' => ['Permission'],
      *       'relation' => [
      *           'name' => 'photos',
      *           'type' => 'PHOTO',
      *           'direction' => 'out',
      *       ],
      *       'values' => [
      *           // A mix of models and attributes, doesn't matter really..
      *           ['url' => '', 'caption' => ''],
      *           ['url' => '', 'caption' => '']
      *       ]
      *  ]
      */
     $related = [];
     foreach ($relations as $relation => $values) {
         $name = $relation;
         // Get the relation by calling the model's relationship function.
         if (!method_exists($this->model, $relation)) {
             throw new QueryException("The relation method {$relation}() does not exist on " . get_class($this->model));
         }
         $relationship = $this->model->{$relation}();
         // Bring the model from the relationship.
         $relatedModel = $relationship->getRelated();
         // We will first check to see what the dev have passed as values
         // so that we make sure that we have an array moving forward
         // In the case of a model Id or an associative array or a Model instance it means that
         // this is probably a One-To-One relationship or the dev decided not to add
         // multiple records as relations so we'll wrap it up in an array.
         if (!is_array($values) || Helpers::isAssocArray($values) || $values instanceof Model) {
             $values = [$values];
         }
         $label = $relationship->getRelated()->getTable();
         $direction = $relationship->getEdgeDirection();
         $type = $relationship->getRelationType();
         // Hold the models that we need to attach
         $attach = [];
         // Hold the models that we need to create
         $create = [];
         // Separate the models that needs to be attached from the ones that needs
         // to be created.
         foreach ($values as $value) {
             // If this is a Model then the $exists property will indicate what we need
             // so we'll add its id to be attached.
             if ($value instanceof Model and $value->exists === true) {
                 $attach[] = $value->getKey();
             } elseif ($value instanceof Collection) {
                 $attach = array_merge($attach, $value->lists('id'));
             } elseif (!is_array($value) && !$value instanceof Model) {
                 $attach[] = intval($value);
             } else {
                 $create[] = $this->prepareForCreation($relatedModel, $value);
             }
         }
         $relation = compact('name', 'type', 'direction');
         $related[] = compact('relation', 'label', 'create', 'attach');
     }
     $result = $this->query->createWith($model, $related);
     $models = $this->resultsToModels($this->model->getConnectionName(), $result);
     return !empty($models) ? reset($models) : null;
 }
 public static function createWith(array $attributes, array $relations, array $options = [])
 {
     // we need to fire model events on all the models that are involved with our operaiton,
     // including the ones from the relations, starting with this model.
     $me = new static();
     $models = [$me];
     $query = static::query();
     $grammar = $query->getQuery()->getGrammar();
     // add parent model's mutation constraints
     $label = $grammar->modelAsNode($me->getDefaultNodeLabel());
     $query->addManyMutation($label, $me);
     // setup relations
     foreach ($relations as $relation => $values) {
         $related = $me->{$relation}()->getRelated();
         // if the relation holds the attributes directly instead of an array
         // of attributes, we transform it into an array of attributes.
         if (!is_array($values) || Helpers::isAssocArray($values)) {
             $values = [$values];
         }
         // create instances with the related attributes so that we fire model
         // events on each of them.
         foreach ($values as $relatedModel) {
             // one may pass in either instances or arrays of attributes, when we get
             // attributes we will dynamically fill a new model instance of the related model.
             if (is_array($relatedModel)) {
                 $relatedModel = $related->fill($relatedModel);
             }
             $models[] = $relatedModel;
             $query->addManyMutation($relation, $related);
         }
     }
     // fire 'creating' and 'saving' events on all models.
     foreach ($models as $model) {
         // we will fire model events on actual models, however attached models using IDs will not be considered.
         if ($model instanceof Model) {
             if ($model->fireModelEvent('creating') === false) {
                 return false;
             }
             if ($model->fireModelEvent('saving') === false) {
                 return false;
             }
         }
     }
     // run the query and create the records.
     $result = $query->createWith($attributes, $relations);
     // take the parent model that was created out of the results array based on
     // this model's label.
     $created = reset($result[$label]);
     // fire 'saved' and 'created' events on parent model.
     $created->finishSave($options);
     $created->fireModelEvent('created', false);
     // set related models as relations on the parent model.
     foreach ($relations as $method => $values) {
         $relation = $created->{$method}();
         // is this a one-to-one relation ? If so then we add the model directly,
         // otherwise we create a collection of the loaded models.
         $related = new Collection($result[$method]);
         // fire model events 'created' and 'saved' on related models.
         $related->each(function ($model) use($options) {
             $model->finishSave($options);
             $model->fireModelEvent('created', false);
         });
         // when the relation is 'One' instead of 'Many' we will only return the retrieved instance
         // instead of colletion.
         if ($relation instanceof OneRelation || $relation instanceof HasOne || $relation instanceof BelongsTo) {
             $related = $related->first();
         }
         $created->setRelation($method, $related);
     }
     return $created;
 }