push()`. * * @package october\backend * @author Alexey Bobkov, Samuel Georges */ trait ResponsiveSaver { /** * @var array List of prepared models that require saving. */ protected $modelsToSave = []; /** * Takes a model and fills it with data from a multidimensional array. * If an attribute is found to be a relationship, that relationship * is also filled. * * $modelsToSave = $this->prepareModelsToSave($model, [...]); * * foreach ($modelsToSave as $modelToSave) { * $modelToSave->save(); * } * * @param \October\Rain\Database\Model $model Model to fill. * @param array $saveData Attribute values to fill model. * @return array The collection of models to save. */ protected function prepareModelsToSave($model, $saveData) { $this->modelsToSave = []; $this->setModelAttributes($model, $saveData); $this->modelsToSave = array_reverse($this->modelsToSave); return $this->modelsToSave; } /** * Sets a data collection to a model attributes, relations are also set. * * @param \October\Rain\Database\Model $model Model to fill. * @param array $saveData Attribute values to fill model. * @return void */ protected function setModelAttributes($model, $saveData) { $this->modelsToSave[] = $model; if (!is_array($saveData)) { return; } if ($model instanceof HalcyonModel) { $model->fill($saveData); return; } $attributesToPurge = []; $singularTypes = ['belongsTo', 'hasOne', 'morphTo', 'morphOne']; foreach ($saveData as $attribute => $value) { $isNested = $attribute == 'pivot' || ( $model->hasRelation($attribute) && in_array($model->getRelationType($attribute), $singularTypes) ); if ($isNested && is_array($value)) { $this->setModelAttributes($model->{$attribute}, $value); } elseif ($value !== FormField::NO_SAVE_DATA) { if (Str::startsWith($attribute, '_')) { $attributesToPurge[] = $attribute; } $model->{$attribute} = $value; } } if ($attributesToPurge) { $this->deferPurgedSaveAttributes($model, $attributesToPurge); } } /** * Removes an array of attributes from the model. If the model implements * the Purgeable trait, this is preferred over the internal logic. * * @param \October\Rain\Database\Model $model Model to adjust. * @param array $attributesToPurge Attribute values to remove from the model. * @return void */ protected function deferPurgedSaveAttributes($model, $attributesToPurge) { if (!is_array($attributesToPurge)) { return; } /* * Compatibility with Purgeable trait: * This will give the ability to restore purged attributes * and make them available again if necessary. */ if (method_exists($model, 'getPurgeableAttributes')) { $model->addPurgeable($attributesToPurge); } else { $model->bindEventOnce('model.saveInternal', function () use ($model, $attributesToPurge) { foreach ($attributesToPurge as $attribute) { unset($model->attributes[$attribute]); } }); } } }