eners() { if ( ! isset(static::$dispatcher)) { return; } $instance = new static; foreach ($instance->getObservableEvents() as $event) { static::$dispatcher->forget("eloquent.{$event}: " . static::class); } } /** * Register a model event with the dispatcher. * * @param string $event * @param \Closure|string $callback * @param int $priority * * @return void */ protected static function registerModelEvent($event, $callback, $priority = 0) { if (isset(static::$dispatcher)) { $name = static::class; static::$dispatcher->listen("eloquent.{$event}: {$name}", $callback, $priority); } } /** * Get the observable event names. * * @return array */ public function getObservableEvents() { return array_merge( [ 'creating', 'created', 'updating', 'updated', 'deleting', 'deleted', 'saving', 'saved', 'restoring', 'restored', ], $this->observables ); } /** * Set the observable event names. * * @param array $observables * * @return $this */ public function setObservableEvents(array $observables) { $this->observables = $observables; return $this; } /** * Add an observable event name. * * @param array|mixed $observables * * @return void */ public function addObservableEvents($observables) { $observables = is_array($observables) ? $observables : func_get_args(); $this->observables = array_unique(array_merge($this->observables, $observables)); } /** * Remove an observable event name. * * @param array|mixed $observables * * @return void */ public function removeObservableEvents($observables) { $observables = is_array($observables) ? $observables : func_get_args(); $this->observables = array_diff($this->observables, $observables); } /** * Increment a column's value by a given amount. * * @param string $column * @param int $amount * @param array $extra * * @return int */ protected function increment($column, $amount = 1, array $extra = []) { return $this->incrementOrDecrement($column, $amount, $extra, 'increment'); } /** * Decrement a column's value by a given amount. * * @param string $column * @param int $amount * @param array $extra * * @return int */ protected function decrement($column, $amount = 1, array $extra = []) { return $this->incrementOrDecrement($column, $amount, $extra, 'decrement'); } /** * Run the increment or decrement method on the model. * * @param string $column * @param int $amount * @param array $extra * @param string $method * * @return int */ protected function incrementOrDecrement($column, $amount, $extra, $method) { $query = $this->newQuery(); if ( ! $this->exists) { return $query->{$method}($column, $amount, $extra); } $this->incrementOrDecrementAttributeValue($column, $amount, $method); return $query->where($this->getKeyName(), $this->getKey())->{$method}($column, $amount, $extra); } /** * Increment the underlying attribute value and sync with original. * * @param string $column * @param int $amount * @param string $method * * @return void */ protected function incrementOrDecrementAttributeValue($column, $amount, $method) { $this->{$column} = $this->{$column} + ($method == 'increment' ? $amount : $amount * -1); $this->syncOriginalAttribute($column); } /** * Update the model in the database. * * @param array $attributes * @param array $options * * @return bool|int */ public function update(array $attributes = [], array $options = []) { if ( ! $this->exists) { return false; } return $this->fill($attributes)->save($options); } /** * Save the model and all of its relationships. * * @return bool */ public function push() { if ( ! $this->save()) { return false; } // To sync all of the relationships to the database, we will simply spin through // the relationships and save each model via this "push" method, which allows // us to recurse into all of these nested relations for the model instance. foreach ($this->relations as $models) { $models = $models instanceof Collection ? $models->all() : [$models]; foreach (array_filter($models) as $model) { if ( ! $model->push()) { return false; } } } return true; } /** * Save the model to the database. * * @param array $options * * @return bool */ public function save(array $options = []) { $query = $this->newQueryWithoutScopes(); // If the "saving" event returns false we'll bail out of the save and return // false, indicating that the save failed. This provides a chance for any // listeners to cancel save operations if validations fail or whatever. if ($this->fireModelEvent('saving') === false) { return false; } // If the model already exists in the database we can just update our record // that is already in this database using the current IDs in this "where" // clause to only update this model. Otherwise, we'll just insert them. if ($this->exists) { $saved = $this->performUpdate($query, $options); } // If the model is brand new, we'll insert it into our database and set the // ID attribute on the model to the value of the newly inserted row's ID // which is typically an auto-increment value managed by the database. else { $saved = $this->performInsert($query, $options); } if ($saved) { $this->finishSave($options); } return $saved; } /** * Save the model to the database using transaction. * * @param array $options * * @return bool * * @throws \Throwable */ public function saveOrFail(array $options = []) { return $this->getConnection()->transaction(function () use ($options) { return $this->save($options); }); } /** * Finish processing on a successful save operation. * * @param array $options * * @return void */ protected function finishSave(array $options) { $this->fireModelEvent('saved', false); $this->syncOriginal(); if (Arr::get($options, 'touch', true)) { $this->touchOwners(); } } /** * Perform a model update operation. * * @param \NinjaTables\Framework\Database\Eloquent\Builder $query * @param array $options * * @return bool */ protected function performUpdate(Builder $query, array $options = []) { $dirty = $this->getDirty(); if (count($dirty) > 0) { // If the updating event returns false, we will cancel the update operation so // developers can hook Validation systems into their models and cancel this // operation if the model does not pass validation. Otherwise, we update. if ($this->fireModelEvent('updating') === false) { return false; } // First we need to create a fresh query instance and touch the creation and // update timestamp on the model which are maintained by us for developer // convenience. Then we will just continue saving the model instances. if ($this->timestamps && Arr::get($options, 'timestamps', true)) { $this->updateTimestamps(); } // Once we have run the update operation, we will fire the "updated" event for // this model instance. This will allow developers to hook into these after // models are updated, giving them a chance to do any special processing. $dirty = $this->getDirty(); if (count($dirty) > 0) { $numRows = $this->setKeysForSaveQuery($query)->update($dirty); $this->fireModelEvent('updated', false); } } return true; } /** * Perform a model insert operation. * * @param \NinjaTables\Framework\Database\Eloquent\Builder $query * @param array $options * * @return bool */ protected function performInsert(Builder $query, array $options = []) { if ($this->fireModelEvent('creating') === false) { return false; } // First we'll need to create a fresh query instance and touch the creation and // update timestamps on this model, which are maintained by us for developer // convenience. After, we will just continue saving these model instances. if ($this->timestamps && Arr::get($options, 'timestamps', true)) { $this->updateTimestamps(); } // If the model has an incrementing key, we can use the "insertGetId" method on // the query builder, which will give us back the final inserted ID for this // table from the database. Not all tables have to be incrementing though. $attributes = $this->attributes; if ($this->getIncrementing()) { $this->insertAndSetId($query, $attributes); } // If the table isn't incrementing we'll simply insert these attributes as they // are. These attribute arrays must contain an "id" column previously placed // there by the developer as the manually determined key for these models. else { $query->insert($attributes); } // We will go ahead and set the exists property to true, so that it is set when // the created event is fired, just in case the developer tries to update it // during the event. This will allow them to do so and run an update here. $this->exists = true; $this->wasRecentlyCreated = true; $this->fireModelEvent('created', false); return true; } /** * Insert the given attributes and set the ID on the model. * * @param \NinjaTables\Framework\Database\Eloquent\Builder $query * @param array $attributes * * @return void */ protected function insertAndSetId(Builder $query, $attributes) { $id = $query->insertGetId($attributes, $keyName = $this->getKeyName()); $this->setAttribute($keyName, $id); } /** * Touch the owning relations of the model. * * @return void */ public function touchOwners() { foreach ($this->touches as $relation) { $this->$relation()->touch(); if ($this->$relation instanceof self) { $this->$relation->fireModelEvent('saved', false); $this->$relation->touchOwners(); } elseif ($this->$relation instanceof Collection) { $this->$relation->each(function (Model $relation) { $relation->touchOwners(); }); } } } /** * Determine if the model touches a given relation. * * @param string $relation * * @return bool */ public function touches($relation) { return in_array($relation, $this->touches); } /** * Fire the given event for the model. * * @param string $event * @param bool $halt * * @return mixed */ protected function fireModelEvent($event, $halt = true) { if ( ! isset(static::$dispatcher)) { return true; } // We will append the names of the class to the event to distinguish it from // other model events that are fired, allowing us to listen on each model // event set individually instead of catching event for all the models. $event = "eloquent.{$event}: " . static::class; $method = $halt ? 'until' : 'fire'; return static::$dispatcher->$method($event, $this); } /** * Set the keys for a save update query. * * @param \NinjaTables\Framework\Database\Eloquent\Builder $query * * @return \NinjaTables\Framework\Database\Eloquent\Builder */ protected function setKeysForSaveQuery(Builder $query) { $query->where($this->getKeyName(), '=', $this->getKeyForSaveQuery()); return $query; } /** * Get the primary key value for a save query. * * @return mixed */ protected function getKeyForSaveQuery() { if (isset($this->original[$this->getKeyName()])) { return $this->original[$this->getKeyName()]; } return $this->getAttribute($this->getKeyName()); } /** * Update the model's update timestamp. * * @return bool */ public function touch() { if ( ! $this->timestamps) { return false; } $this->updateTimestamps(); return $this->save(); } /** * Update the creation and update timestamps. * * @return void */ protected function updateTimestamps() { $time = $this->freshTimestamp(); if ( ! $this->isDirty(static::UPDATED_AT)) { $this->setUpdatedAt($time); } if ( ! $this->exists && ! $this->isDirty(static::CREATED_AT)) { $this->setCreatedAt($time); } } /** * Set the value of the "created at" attribute. * * @param mixed $value * * @return $this */ public function setCreatedAt($value) { $this->{static::CREATED_AT} = $value; return $this; } /** * Set the value of the "updated at" attribute. * * @param mixed $value * * @return $this */ public function setUpdatedAt($value) { $this->{static::UPDATED_AT} = $value; return $this; } /** * Get the name of the "created at" column. * * @return string */ public function getCreatedAtColumn() { return static::CREATED_AT; } /** * Get the name of the "updated at" column. * * @return string */ public function getUpdatedAtColumn() { return static::UPDATED_AT; } /** * Get a fresh timestamp for the model. * * @return \NinjaTables\Framework\Database\Orm\DateTime */ public function freshTimestamp() { return new DateTime('now', $this->getTimezone()); } /** * Get a fresh timestamp for the model. * * @return string */ public function freshTimestampString() { return $this->fromDateTime($this->freshTimestamp()); } /** * Get a new query builder for the model's table. * * @return \NinjaTables\Framework\Database\Eloquent\Builder */ public function newQuery() { $builder = $this->newQueryWithoutScopes(); foreach ($this->getGlobalScopes() as $identifier => $scope) { $builder->withGlobalScope($identifier, $scope); } return $builder; } /** * Get a new query instance without a given scope. * * @param \NinjaTables\Framework\Database\Eloquent\Scope|string $scope * * @return \NinjaTables\Framework\Database\Eloquent\Builder */ public function newQueryWithoutScope($scope) { $builder = $this->newQuery(); return $builder->withoutGlobalScope($scope); } /** * Get a new query builder that doesn't have any global scopes. * * @return \NinjaTables\Framework\Database\Eloquent\Builder|static */ public function newQueryWithoutScopes() { $builder = $this->newEloquentBuilder( $this->newBaseQueryBuilder() ); // Once we have the query builders, we will set the model instances so the // builder can easily access any information it may need from the model // while it is constructing and executing various queries against it. return $builder->setModel($this)->with($this->with); } /** * Create a new Eloquent query builder for the model. * * @param \NinjaTables\Framework\Database\Query\Builder $query * * @return \NinjaTables\Framework\Database\Eloquent\Builder|static */ public function newEloquentBuilder($query) { return new Builder($query); } /** * Get a new query builder instance for the connection. * * @return \NinjaTables\Framework\Database\Query\Builder */ protected function newBaseQueryBuilder() { $conn = $this->getConnection(); $grammar = $conn->getQueryGrammar(); return new QueryBuilder($conn, $grammar, $conn->getPostProcessor()); } /** * Create a new Eloquent Collection instance. * * @param array $models * * @return \NinjaTables\Framework\Database\Eloquent\Collection */ public function newCollection(array $models = []) { return new Collection($models); } /** * Create a new pivot model instance. * * @param \NinjaTables\Framework\Database\Eloquent\Model $parent * @param array $attributes * @param string $table * @param bool $exists * * @return \NinjaTables\Framework\Database\Eloquent\Relations\Pivot */ public function newPivot(Model $parent, array $attributes, $table, $exists) { return new Pivot($parent, $attributes, $table, $exists); } /** * Get the table associated with the model. * * @return string */ public function getTable() { if (isset($this->table)) { return $this->table; } return str_replace('\\', '', Str::snake(Str::plural(static::classBasename($this)))); } /** * Set the table associated with the model. * * @param string $table * * @return $this */ public function setTable($table) { $this->table = $table; return $this; } /** * Get the value of the model's primary key. * * @return mixed */ public function getKey() { return $this->getAttribute($this->getKeyName()); } /** * Get the queueable identity for the entity. * * @return mixed */ public function getQueueableId() { return $this->getKey(); } /** * Get the primary key for the model. * * @return string */ public function getKeyName() { return $this->primaryKey; } /** * Set the primary key for the model. * * @param string $key * * @return $this */ public function setKeyName($key) { $this->primaryKey = $key; return $this; } /** * Get the table qualified key name. * * @return string */ public function getQualifiedKeyName() { return $this->getTable() . '.' . $this->getKeyName(); } /** * Get the value of the model's route key. * * @return mixed */ public function getRouteKey() { return $this->getAttribute($this->getRouteKeyName()); } /** * Get the route key for the model. * * @return string */ public function getRouteKeyName() { return $this->getKeyName(); } /** * Determine if the model uses timestamps. * * @return bool */ public function usesTimestamps() { return $this->timestamps; } /** * Get the polymorphic relationship columns. * * @param string $name * @param string $type * @param string $id * * @return array */ protected function getMorphs($name, $type, $id) { $type = $type ?: $name . '_type'; $id = $id ?: $name . '_id'; return [$type, $id]; } /** * Get the class name for polymorphic relations. * * @return string */ public function getMorphClass() { $morphMap = Relation::morphMap(); $class = static::class; if ( ! empty($morphMap) && in_array($class, $morphMap)) { return array_search($class, $morphMap, true); } return $this->morphClass ?: $class; } /** * Get the number of models to return per page. * * @return int */ public function getPerPage() { return $this->perPage; } /** * Set the number of models to return per page. * * @param int $perPage * * @return $this */ public function setPerPage($perPage) { $this->perPage = $perPage; return $this; } /** * Get the default foreign key name for the model. * * @return string */ public function getForeignKey() { return Str::snake(static::classBasename($this)) . '_id'; } /** * Get the hidden attributes for the model. * * @return array */ public function getHidden() { return $this->hidden; } /** * Set the hidden attributes for the model. * * @param array $hidden * * @return $this */ public function setHidden(array $hidden) { $this->hidden = $hidden; return $this; } /** * Add hidden attributes for the model. * * @param array|string|null $attributes * * @return void */ public function addHidden($attributes = null) { $attributes = is_array($attributes) ? $attributes : func_get_args(); $this->hidden = array_merge($this->hidden, $attributes); } /** * Make the given, typically hidden, attributes visible. * * @param array|string $attributes * * @return $this */ public function makeVisible($attributes) { $this->hidden = array_diff($this->hidden, (array)$attributes); if ( ! empty($this->visible)) { $this->addVisible($attributes); } return $this; } /** * Make the given, typically visible, attributes hidden. * * @param array|string $attributes * * @return $this */ public function makeHidden($attributes) { $attributes = (array)$attributes; $this->visible = array_diff($this->visible, $attributes); $this->hidden = array_unique(array_merge($this->hidden, $attributes)); return $this; } /** * Make the given, typically hidden, attributes visible. * * @param array|string $attributes * * @return $this * * @deprecated since version 5.2. Use the "makeVisible" method directly. */ public function withHidden($attributes) { return $this->makeVisible($attributes); } /** * Get the visible attributes for the model. * * @return array */ public function getVisible() { return $this->visible; } /** * Set the visible attributes for the model. * * @param array $visible * * @return $this */ public function setVisible(array $visible) { $this->visible = $visible; return $this; } /** * Add visible attributes for the model. * * @param array|string|null $attributes * * @return void */ public function addVisible($attributes = null) { $attributes = is_array($attributes) ? $attributes : func_get_args(); $this->visible = array_merge($this->visible, $attributes); } /** * Set the accessors to append to model arrays. * * @param array $appends * * @return $this */ public function setAppends(array $appends) { $this->appends = $appends; return $this; } /** * Get the fillable attributes for the model. * * @return array */ public function getFillable() { return $this->fillable; } /** * Set the fillable attributes for the model. * * @param array $fillable * * @return $this */ public function fillable(array $fillable) { $this->fillable = $fillable; return $this; } /** * Get the guarded attributes for the model. * * @return array */ public function getGuarded() { return $this->guarded; } /** * Set the guarded attributes for the model. * * @param array $guarded * * @return $this */ public function guard(array $guarded) { $this->guarded = $guarded; return $this; } /** * Disable all mass assignable restrictions. * * @param bool $state * * @return void */ public static function unguard($state = true) { static::$unguarded = $state; } /** * Enable the mass assignment restrictions. * * @return void */ public static function reguard() { static::$unguarded = false; } /** * Determine if current state is "unguarded". * * @return bool */ public static function isUnguarded() { return static::$unguarded; } /** * Run the given callable while being unguarded. * * @param callable $callback * * @return mixed */ public static function unguarded(callable $callback) { if (static::$unguarded) { return $callback(); } static::unguard(); try { return $callback(); } finally { static::reguard(); } } /** * Determine if the given attribute may be mass assigned. * * @param string $key * * @return bool */ public function isFillable($key) { if (static::$unguarded) { return true; } // If the key is in the "fillable" array, we can of course assume that it's // a fillable attribute. Otherwise, we will check the guarded array when // we need to determine if the attribute is black-listed on the model. if (in_array($key, $this->getFillable())) { return true; } if ($this->isGuarded($key)) { return false; } return empty($this->getFillable()) && ! Str::startsWith($key, '_'); } /** * Determine if the given key is guarded. * * @param string $key * * @return bool */ public function isGuarded($key) { return in_array($key, $this->getGuarded()) || $this->getGuarded() == ['*']; } /** * Determine if the model is totally guarded. * * @return bool */ public function totallyGuarded() { return count($this->getFillable()) == 0 && $this->getGuarded() == ['*']; } /** * Remove the table name from a given key. * * @param string $key * * @return string */ protected function removeTableFromKey($key) { if ( ! Str::contains($key, '.')) { return $key; } return Helper::last(explode('.', $key)); } /** * Get the relationships that are touched on save. * * @return array */ public function getTouchedRelations() { return $this->touches; } /** * Set the relationships that are touched on save. * * @param array $touches * * @return $this */ public function setTouchedRelations(array $touches) { $this->touches = $touches; return $this; } /** * Get the value indicating whether the IDs are incrementing. * * @return bool */ public function getIncrementing() { return $this->incrementing; } /** * Set whether IDs are incrementing. * * @param bool $value * * @return $this */ public function setIncrementing($value) { $this->incrementing = $value; return $this; } /** * Convert the model instance to JSON. * * @param int $options * * @return string */ public function toJson($options = 0) { return json_encode($this->jsonSerialize(), $options); } /** * Convert the object into something JSON serializable. * * @return array */ #[\ReturnTypeWillChange] public function jsonSerialize() { return $this->toArray(); } /** * Convert the model instance to an array. * * @return array */ public function toArray() { $attributes = $this->attributesToArray(); return array_merge($attributes, $this->relationsToArray()); } /** * Convert the model's attributes to an array. * * @return array */ public function attributesToArray() { $attributes = $this->getArrayableAttributes(); // If an attribute is a date, we will cast it to a string after converting it // to a DateTime / Carbon instance. This is so we will get some consistent // formatting while accessing attributes vs. arraying / JSONing a model. foreach ($this->getDates() as $key) { if ( ! isset($attributes[$key])) { continue; } $attributes[$key] = $this->serializeDate( $this->asDateTime($attributes[$key]) ); } $mutatedAttributes = $this->getMutatedAttributes(); // We want to spin through all the mutated attributes for this model and call // the mutator for the attribute. We cache off every mutated attributes so // we don't have to constantly check on attributes that actually change. foreach ($mutatedAttributes as $key) { if ( ! array_key_exists($key, $attributes)) { continue; } $attributes[$key] = $this->mutateAttributeForArray( $key, $attributes[$key] ); } // Next we will handle any casts that have been setup for this model and cast // the values to their appropriate type. If the attribute has a mutator we // will not perform the cast on those attributes to avoid any confusion. foreach ($this->getCasts() as $key => $value) { if ( ! array_key_exists($key, $attributes) || in_array($key, $mutatedAttributes)) { continue; } $attributes[$key] = $this->castAttribute( $key, $attributes[$key] ); if ($attributes[$key] && ($value === 'date' || $value === 'datetime')) { $attributes[$key] = $this->serializeDate($attributes[$key]); } } // Here we will grab all of the appended, calculated attributes to this model // as these attributes are not really in the attributes array, but are run // when we need to array or JSON the model for convenience to the coder. foreach ($this->getArrayableAppends() as $key) { $attributes[$key] = $this->mutateAttributeForArray($key, null); } return $attributes; } /** * Get an attribute array of all arrayable attributes. * * @return array */ protected function getArrayableAttributes() { return $this->getArrayableItems($this->attributes); } /** * Get all of the appendable values that are arrayable. * * @return array */ protected function getArrayableAppends() { if ( ! count($this->appends)) { return []; } return $this->getArrayableItems( array_combine($this->appends, $this->appends) ); } /** * Get the model's relationships in array form. * * @return array */ public function relationsToArray() { $attributes = []; foreach ($this->getArrayableRelations() as $key => $value) { // If the values implements the Arrayable interface we can just call this // toArray method on the instances which will convert both models and // collections to their proper array form and we'll set the values. if ($value instanceof ArrayableInterface) { $relation = $value->toArray(); } // If the value is null, we'll still go ahead and set it in this list of // attributes since null is used to represent empty relationships if // if it a has one or belongs to type relationships on the models. elseif (is_null($value)) { $relation = $value; } // If the relationships snake-casing is enabled, we will snake case this // key so that the relation attribute is snake cased in this returned // array to the developers, making this consistent with attributes. if (static::$snakeAttributes) { $key = Str::snake($key); } // If the relation value has been set, we will set it on this attributes // list for returning. If it was not arrayable or null, we'll not set // the value on the array because it is some type of invalid value. if (isset($relation) || is_null($value)) { $attributes[$key] = $relation; } unset($relation); } return $attributes; } /** * Get an attribute array of all arrayable relations. * * @return array */ protected function getArrayableRelations() { return $this->getArrayableItems($this->relations); } /** * Get an attribute array of all arrayable values. * * @param array $values * * @return array */ protected function getArrayableItems(array $values) { if (count($this->getVisible()) > 0) { $values = array_intersect_key($values, array_flip($this->getVisible())); } if (count($this->getHidden()) > 0) { $values = array_diff_key($values, array_flip($this->getHidden())); } return $values; } /** * Get an attribute from the model. * * @param string $key * * @return mixed */ public function getAttribute($key) { if (array_key_exists($key, $this->attributes) || $this->hasGetMutator($key)) { return $this->getAttributeValue($key); } return $this->getRelationValue($key); } /** * Get a plain attribute (not a relationship). * * @param string $key * * @return mixed */ public function getAttributeValue($key) { $value = $this->getAttributeFromArray($key); // If the attribute has a get mutator, we will call that then return what // it returns as the value, which is useful for transforming values on // retrieval from the model to a form that is more useful for usage. if ($this->hasGetMutator($key)) { return $this->mutateAttribute($key, $value); } // If the attribute exists within the cast array, we will convert it to // an appropriate native PHP type dependant upon the associated value // given with the key in the pair. Dayle made this comment line up. if ($this->hasCast($key)) { return $this->castAttribute($key, $value); } // If the attribute is listed as a date, we will convert it to a DateTime // instance on retrieval, which makes it quite convenient to work with // date fields without having to create a mutator for each property. if (in_array($key, $this->getDates()) && ! is_null($value)) { return $this->asDateTime($value); } return $value; } /** * Get a relationship. * * @param string $key * * @return mixed */ public function getRelationValue($key) { // If the key already exists in the relationships array, it just means the // relationship has already been loaded, so we'll just return it out of // here because there is no need to query within the relations twice. if ($this->relationLoaded($key)) { return $this->relations[$key]; } // If the "attribute" exists as a method on the model, we will just assume // it is a relationship and will load and return results from the query // and hydrate the relationship's value on the "relationships" array. if (method_exists($this, $key)) { return $this->getRelationshipFromMethod($key); } } /** * Get an attribute from the $attributes array. * * @param string $key * * @return mixed */ protected function getAttributeFromArray($key) { if (array_key_exists($key, $this->attributes)) { return $this->attributes[$key]; } } /** * Get a relationship value from a method. * * @param string $method * * @return mixed * * @throws \LogicException */ protected function getRelationshipFromMethod($method) { $relations = $this->$method(); if ( ! $relations instanceof Relation) { throw new LogicException('Relationship method must return an object of type ' . 'NinjaTables\Framework\Database\Eloquent\Relations\Relation'); } $this->setRelation($method, $results = $relations->getResults()); return $results; } /** * Determine if a get mutator exists for an attribute. * * @param string $key * * @return bool */ public function hasGetMutator($key) { return method_exists($this, 'get' . Str::studly($key) . 'Attribute'); } /** * Get the value of an attribute using its mutator. * * @param string $key * @param mixed $value * * @return mixed */ protected function mutateAttribute($key, $value) { return $this->{'get' . Str::studly($key) . 'Attribute'}($value); } /** * Get the value of an attribute using its mutator for array conversion. * * @param string $key * @param mixed $value * * @return mixed */ protected function mutateAttributeForArray($key, $value) { $value = $this->mutateAttribute($key, $value); return $value instanceof ArrayableInterface ? $value->toArray() : $value; } /** * Determine whether an attribute should be cast to a native type. * * @param string $key * @param array|string|null $types * * @return bool */ public function hasCast($key, $types = null) { if (array_key_exists($key, $this->getCasts())) { return $types ? in_array($this->getCastType($key), (array)$types, true) : true; } return false; } /** * Get the casts array. * * @return array */ public function getCasts() { if ($this->getIncrementing()) { return array_merge([ $this->getKeyName() => $this->keyType, ], $this->casts); } return $this->casts; } /** * Determine whether a value is Date / DateTime castable for inbound manipulation. * * @param string $key * * @return bool */ protected function isDateCastable($key) { return $this->hasCast($key, ['date', 'datetime']); } /** * Determine whether a value is JSON castable for inbound manipulation. * * @param string $key * * @return bool */ protected function isJsonCastable($key) { return $this->hasCast($key, ['array', 'json', 'object', 'collection']); } /** * Get the type of cast for a model attribute. * * @param string $key * * @return string */ protected function getCastType($key) { return trim(strtolower($this->getCasts()[$key])); } /** * Cast an attribute to a native PHP type. * * @param string $key * @param mixed $value * * @return mixed */ protected function castAttribute($key, $value) { if (is_null($value)) { return $value; } switch ($this->getCastType($key)) { case 'int': case 'integer': return (int)$value; case 'real': case 'float': case 'double': return (float)$value; case 'string': return (string)$value; case 'bool': case 'boolean': return (bool)$value; case 'object': return $this->fromJson($value, true); case 'array': case 'json': return $this->fromJson($value); case 'collection': return new BaseCollection($this->fromJson($value)); case 'date': case 'datetime': return $this->asDateTime($value); case 'timestamp': return $this->asTimeStamp($value); default: return $value; } } /** * Set a given attribute on the model. * * @param string $key * @param mixed $value * * @return $this */ public function setAttribute($key, $value) { // First we will check for the presence of a mutator for the set operation // which simply lets the developers tweak the attribute as it is set on // the model, such as "json_encoding" an listing of data for storage. if ($this->hasSetMutator($key)) { $method = 'set' . Str::studly($key) . 'Attribute'; return $this->{$method}($value); } // If an attribute is listed as a "date", we'll convert it from a DateTime // instance into a form proper for storage on the database tables using // the connection grammar's date format. We will auto set the values. elseif ($value && (in_array($key, $this->getDates()) || $this->isDateCastable($key))) { $value = $this->fromDateTime($value); } if ($this->isJsonCastable($key) && ! is_null($value)) { $value = $this->asJson($value); } $this->attributes[$key] = $value; return $this; } /** * Determine if a set mutator exists for an attribute. * * @param string $key * * @return bool */ public function hasSetMutator($key) { return method_exists($this, 'set' . Str::studly($key) . 'Attribute'); } /** * Get the attributes that should be converted to dates. * * @return array */ public function getDates() { $defaults = [static::CREATED_AT, static::UPDATED_AT]; return $this->timestamps ? array_merge($this->dates, $defaults) : $this->dates; } /** * Convert a DateTime to a storable string. * * @param \DateTime|int $value * * @return string */ public function fromDateTime($value) { $format = $this->getDateFormat(); $value = $this->asDateTime($value); return $value->format($format); } /** * Return a timestamp as DateTime object. * * @param mixed $value * * @return \DateTime */ protected function asDateTime($value) { // If this value is already a DateTime instance, we shall just return it as is. if ($value instanceof DateTime) { return $value; } // If the value is already a DateTime instance, we will just skip the rest of // these checks since they will be a waste of time, and hinder performance // when checking the field. We will just return the DateTime right away. if ($value instanceof DateTimeInterface) { return new DateTime( $value->format('Y-m-d H:i:s.u'), $value->getTimeZone() ); } // If this value is an integer, we will assume it is a UNIX timestamp's value // and format a DateTime object from this timestamp. This allows flexibility // when defining your date fields as they might be UNIX timestamps here. if (is_numeric($value)) { $dateTime = new DateTime(); $dateTime->setTimestamp($value); return $dateTime; } // If the value is in simply year, month, day format, we will instantiate the // DateTime instances from that format. Again, this provides for simple date // fields on the database. if (preg_match('/^(\d{4})-(\d{1,2})-(\d{1,2})$/', $value)) { $dateTime = DateTime::createFromFormat('Y-m-d', $value); $dateTime->setTime(0, 0, 0); return $dateTime; } // Finally, we will just assume this date is in the format used by default on // the database connection and use that format to create the DateTime object // that is returned back out to the developers after we convert it here. return DateTime::createFromFormat($this->getDateFormat(), $value); } /** * Return a timestamp as unix timestamp. * * @param mixed $value * * @return int */ protected function asTimeStamp($value) { return $this->asDateTime($value)->getTimestamp(); } /** * Prepare a date for array / JSON serialization. * * @param \DateTime $date * * @return string */ protected function serializeDate(DateTime $date) { return $date->format($this->getDateFormat()); } /** * Set the date format used by the model. * * @param string $format * * @return $this */ public function setDateFormat($format) { $this->dateFormat = $format; return $this; } /** * Encode the given value as JSON. * * @param mixed $value * * @return string */ protected function asJson($value) { return json_encode($value); } /** * Decode the given JSON back into an array or object. * * @param string $value * @param bool $asObject * * @return mixed */ public function fromJson($value, $asObject = false) { return json_decode($value, ! $asObject); } /** * Clone the model into a new, non-existing instance. * * @param array|null $except * * @return \NinjaTables\Framework\Database\Eloquent\Model */ public function replicate(array $except = null) { $defaults = [ $this->getKeyName(), $this->getCreatedAtColumn(), $this->getUpdatedAtColumn(), ]; $except = $except ? array_unique(array_merge($except, $defaults)) : $defaults; $attributes = Arr::except($this->attributes, $except); $instance = new static; $instance->setRawAttributes($attributes); return $instance->setRelations($this->relations); } /** * Get all of the current attributes on the model. * * @return array */ public function getAttributes() { return $this->attributes; } /** * Set the array of model attributes. No checking is done. * * @param array $attributes * @param bool $sync * * @return $this */ public function setRawAttributes(array $attributes, $sync = false) { $this->attributes = $attributes; if ($sync) { $this->syncOriginal(); } return $this; } /** * Get the model's original attribute values. * * @param string|null $key * @param mixed $default * * @return mixed|array */ public function getOriginal($key = null, $default = null) { return Arr::get($this->original, $key, $default); } /** * Sync the original attributes with the current. * * @return $this */ public function syncOriginal() { $this->original = $this->attributes; return $this; } /** * Sync a single original attribute with its current value. * * @param string $attribute * * @return $this */ public function syncOriginalAttribute($attribute) { $this->original[$attribute] = $this->attributes[$attribute]; return $this; } /** * Determine if the model or given attribute(s) have been modified. * * @param array|string|null $attributes * * @return bool */ public function isDirty($attributes = null) { $dirty = $this->getDirty(); if (is_null($attributes)) { return count($dirty) > 0; } if ( ! is_array($attributes)) { $attributes = func_get_args(); } foreach ($attributes as $attribute) { if (array_key_exists($attribute, $dirty)) { return true; } } return false; } /** * Get the attributes that have been changed since last sync. * * @return array */ public function getDirty() { $dirty = []; foreach ($this->attributes as $key => $value) { if ( ! array_key_exists($key, $this->original)) { $dirty[$key] = $value; } elseif ($value !== $this->original[$key] && ! $this->originalIsNumericallyEquivalent($key)) { $dirty[$key] = $value; } } return $dirty; } /** * Determine if the new and old values for a given key are numerically equivalent. * * @param string $key * * @return bool */ protected function originalIsNumericallyEquivalent($key) { $current = $this->attributes[$key]; $original = $this->original[$key]; return is_numeric($current) && is_numeric($original) && strcmp((string)$current, (string)$original) === 0; } /** * Get all the loaded relations for the instance. * * @return array */ public function getRelations() { return $this->relations; } /** * Get a specified relationship. * * @param string $relation * * @return mixed */ public function getRelation($relation) { return $this->relations[$relation]; } /** * Determine if the given relation is loaded. * * @param string $key * * @return bool */ public function relationLoaded($key) { return array_key_exists($key, $this->relations); } /** * Set the specific relationship in the model. * * @param string $relation * @param mixed $value * * @return $this */ public function setRelation($relation, $value) { $this->relations[$relation] = $value; return $this; } /** * Set the entire relations array on the model. * * @param array $relations * * @return $this */ public function setRelations(array $relations) { $this->relations = $relations; return $this; } /** * Get the database connection for the model. * * @return \NinjaTables\Framework\Database\Connection */ public function getConnection() { return static::resolveConnection($this->getConnectionName()); } /** * Get the current connection name for the model. * * @return string */ public function getConnectionName() { return $this->connection; } /** * Set the connection associated with the model. * * @param string $name * * @return $this */ public function setConnection($name) { $this->connection = $name; return $this; } /** * Resolve a connection instance. * * @param string|null $connection * * @return \NinjaTables\Framework\Database\Connection */ public static function resolveConnection($connection = null) { return static::$resolver->connection($connection); } /** * Get the connection resolver instance. * * @return \NinjaTables\Framework\Database\ConnectionResolverInterface */ public static function getConnectionResolver() { return static::$resolver; } /** * Set the connection resolver instance. * * @param \NinjaTables\Framework\Database\ConnectionResolverInterface $resolver * * @return void */ public static function setConnectionResolver(Resolver $resolver) { static::$resolver = $resolver; } /** * Unset the connection resolver for models. * * @return void */ public static function unsetConnectionResolver() { static::$resolver = null; } /** * Get the event dispatcher instance. * * @return \NinjaTables\Framework\Contracts\Events\Dispatcher */ public static function getEventDispatcher() { return static::$dispatcher; } /** * Set the event dispatcher instance. * * @param \NinjaTables\Framework\Foundation\Dispatcher $dispatcher * * @return void */ public static function setEventDispatcher(Dispatcher $dispatcher) { static::$dispatcher = $dispatcher; } /** * Unset the event dispatcher for models. * * @return void */ public static function unsetEventDispatcher() { static::$dispatcher = null; } /** * Get the mutated attributes for a given instance. * * @return array */ public function getMutatedAttributes() { $class = static::class; if ( ! isset(static::$mutatorCache[$class])) { static::cacheMutatedAttributes($class); } return static::$mutatorCache[$class]; } /** * Extract and cache all the mutated attributes of a class. * * @param string $class * * @return void */ public static function cacheMutatedAttributes($class) { $mutatedAttributes = []; // Here we will extract all of the mutated attributes so that we can quickly // spin through them after we export models to their array form, which we // need to be fast. This'll let us know the attributes that can mutate. if (preg_match_all('/(?<=^|;)get([^;]+?)Attribute(;|$)/', implode(';', get_class_methods($class)), $matches)) { foreach ($matches[1] as $match) { if (static::$snakeAttributes) { $match = Str::snake($match); } $mutatedAttributes[] = lcfirst($match); } } static::$mutatorCache[$class] = $mutatedAttributes; } /** * Dynamically retrieve attributes on the model. * * @param string $key * * @return mixed */ public function __get($key) { return $this->getAttribute($key); } /** * Dynamically set attributes on the model. * * @param string $key * @param mixed $value * * @return void */ public function __set($key, $value) { $this->setAttribute($key, $value); } /** * Determine if the given attribute exists. * * @param mixed $offset * * @return bool */ #[\ReturnTypeWillChange] public function offsetExists($offset) { return isset($this->$offset); } /** * Get the value for a given offset. * * @param mixed $offset * * @return mixed */ #[\ReturnTypeWillChange] public function offsetGet($offset) { return $this->$offset; } /** * Set the value for a given offset. * * @param mixed $offset * @param mixed $value * * @return void */ #[\ReturnTypeWillChange] public function offsetSet($offset, $value) { $this->$offset = $value; } /** * Unset the value for a given offset. * * @param mixed $offset * * @return void */ #[\ReturnTypeWillChange] public function offsetUnset($offset) { unset($this->$offset); } /** * Determine if an attribute or relation exists on the model. * * @param string $key * * @return bool */ public function __isset($key) { return ! is_null($this->getAttribute($key)); } /** * Unset an attribute on the model. * * @param string $key * * @return void */ public function __unset($key) { unset($this->attributes[$key], $this->relations[$key]); } /** * Handle dynamic method calls into the model. * * @param string $method * @param array $parameters * * @return mixed */ public function __call($method, $parameters) { if (in_array($method, ['increment', 'decrement'])) { return call_user_func_array([$this, $method], $parameters); } $query = $this->newQuery(); return call_user_func_array([$query, $method], $parameters); } /** * Handle dynamic static method calls into the method. * * @param string $method * @param array $parameters * * @return mixed */ public static function __callStatic($method, $parameters) { $instance = new static; return call_user_func_array([$instance, $method], $parameters); } /** * Convert the model to its string representation. * * @return string */ public function __toString() { return $this->toJson(); } /** * When a model is being unserialized, check if it needs to be booted. * * @return void */ public function __wakeup() { $this->bootIfNotBooted(); } }
Fatal error: Uncaught Error: Class 'NinjaTables\Framework\Database\Orm\Model' not found in /home/nimaghor/public_html/wp-content/plugins/ninja-tables/vendor/wpfluent/framework/src/WPFluent/Foundation/ComponentBinder.php:117 Stack trace: #0 /home/nimaghor/public_html/wp-content/plugins/ninja-tables/vendor/wpfluent/framework/src/WPFluent/Foundation/ComponentBinder.php(42): NinjaTables\Framework\Foundation\ComponentBinder->bindDataBase() #1 /home/nimaghor/public_html/wp-content/plugins/ninja-tables/vendor/wpfluent/framework/src/WPFluent/Foundation/Application.php(141): NinjaTables\Framework\Foundation\ComponentBinder->bindComponents() #2 /home/nimaghor/public_html/wp-content/plugins/ninja-tables/vendor/wpfluent/framework/src/WPFluent/Foundation/Application.php(75): NinjaTables\Framework\Foundation\Application->bindCoreComponents() #3 /home/nimaghor/public_html/wp-content/plugins/ninja-tables/vendor/wpfluent/framework/src/WPFluent/Foundation/Application.php(30): NinjaTables\Framework\Foundation\Application->bootstrapApplicati in /home/nimaghor/public_html/wp-content/plugins/ninja-tables/vendor/wpfluent/framework/src/WPFluent/Foundation/ComponentBinder.php on line 117