1
0
mirror of https://github.com/flarum/core.git synced 2025-08-07 17:07:19 +02:00

Add model extender (#2100)

This covers default attribute values, date attributes and custom relationships.
This commit is contained in:
Alexander Skvortsov
2020-04-24 09:10:24 -04:00
committed by GitHub
parent c896cd8696
commit 15bed971e6
6 changed files with 452 additions and 15 deletions

View File

@@ -14,6 +14,7 @@ use Flarum\Event\ConfigureModelDefaultAttributes;
use Flarum\Event\GetModelRelationship;
use Illuminate\Database\Eloquent\Model as Eloquent;
use Illuminate\Database\Eloquent\Relations\Relation;
use Illuminate\Support\Arr;
use LogicException;
/**
@@ -46,6 +47,12 @@ abstract class AbstractModel extends Eloquent
*/
protected $afterDeleteCallbacks = [];
public static $customRelations = [];
public static $dateAttributes = [];
public static $defaults = [];
/**
* {@inheritdoc}
*/
@@ -71,13 +78,16 @@ abstract class AbstractModel extends Eloquent
*/
public function __construct(array $attributes = [])
{
$defaults = [];
$this->attributes = Arr::get(static::$defaults, static::class, []);
// Deprecated in beta 13, remove in beta 14.
static::$dispatcher->dispatch(
new ConfigureModelDefaultAttributes($this, $defaults)
new ConfigureModelDefaultAttributes($this, $this->attributes)
);
$this->attributes = $defaults;
$this->attributes = array_map(function ($item) {
return is_callable($item) ? $item() : $item;
}, $this->attributes);
parent::__construct($attributes);
}
@@ -89,19 +99,11 @@ abstract class AbstractModel extends Eloquent
*/
public function getDates()
{
static $dates = [];
static::$dispatcher->dispatch(
new ConfigureModelDates($this, $this->dates)
);
$class = get_class($this);
if (! isset($dates[$class])) {
static::$dispatcher->dispatch(
new ConfigureModelDates($this, $this->dates)
);
$dates[$class] = $this->dates;
}
return $dates[$class];
return array_merge($this->dates, Arr::get(static::$dateAttributes, static::class, []));
}
/**
@@ -139,6 +141,13 @@ abstract class AbstractModel extends Eloquent
*/
protected function getCustomRelation($name)
{
$relation = Arr::get(static::$customRelations, static::class.".$name", null);
if (! is_null($relation)) {
return $relation($this);
}
// Deprecated, remove in beta 14
return static::$dispatcher->until(
new GetModelRelationship($this, $name)
);

View File

@@ -12,6 +12,8 @@ namespace Flarum\Event;
use Flarum\Database\AbstractModel;
/**
* @deprecated in beta 13, removed in beta 14
*
* The `ConfigureModelDates` event is called to retrieve a list of fields for a model
* that should be converted into date objects.
*/

View File

@@ -11,6 +11,9 @@ namespace Flarum\Event;
use Flarum\Database\AbstractModel;
/**
* @deprecated in beta 13, removed in beta 14
*/
class ConfigureModelDefaultAttributes
{
/**

View File

@@ -12,6 +12,8 @@ namespace Flarum\Event;
use Flarum\Database\AbstractModel;
/**
* @deprecated beta 13, use the Model extender instead.
*
* The `GetModelRelationship` event is called to retrieve Relation object for a
* model. Listeners should return an Eloquent Relation object.
*/

171
src/Extend/Model.php Normal file
View File

@@ -0,0 +1,171 @@
<?php
/*
* This file is part of Flarum.
*
* For detailed copyright and license information, please view the
* LICENSE file that was distributed with this source code.
*/
namespace Flarum\Extend;
use Flarum\Database\AbstractModel;
use Flarum\Extension\Extension;
use Illuminate\Contracts\Container\Container;
use Illuminate\Support\Arr;
class Model implements ExtenderInterface
{
private $modelClass;
private $dateAttributes = [];
private $defaults = [];
private $relationships = [];
/**
* @param string $modelClass The ::class attribute of the model you are modifying.
* This model should extend from \Flarum\Database\AbstractModel.
*/
public function __construct(string $modelClass)
{
$this->modelClass = $modelClass;
}
/**
* Add an attribute to be treated as a date.
*
* @param string $attribute
*/
public function dateAttribute(string $attribute)
{
Arr::set(AbstractModel::$dateAttributes, $this->modelClass, array_merge(Arr::get(AbstractModel::$dateAttributes, $this->modelClass, []), [$attribute]));
return $this;
}
/**
* Add a default value for a given attribute, which can be an explicit value, or a closure.
*
* @param string $attribute
* @param mixed $value
*/
public function default(string $attribute, $value)
{
Arr::set(AbstractModel::$defaults, "$this->modelClass.$attribute", $value);
return $this;
}
/**
* Add a relationship from this model to another model.
*
* @param string $name: The name of the relation. This doesn't have to be anything in particular,
* but has to be unique from other relation names for this model, and should
* work as the name of a method.
* @param callable $callable
*
* The callable can be a closure or invokable class, and should accept:
* - $instance: An instance of this model.
*
* The callable should return:
* - $relationship: A Laravel Relationship object. See relevant methods of models
* like \Flarum\User\User for examples of how relationships should be returned.
*/
public function relationship(string $name, callable $callable)
{
Arr::set(AbstractModel::$customRelations, "$this->modelClass.$name", $callable);
return $this;
}
/**
* Establish a simple belongsTo relationship from this model to another model.
* This represents an inverse one-to-one or inverse one-to-many relationship.
* For more complex relationships, use the ->relationship method.
*
* @param string $name: The name of the relation. This doesn't have to be anything in particular,
* but has to be unique from other relation names for this model, and should
* work as the name of a method.
* @param string $related: The ::class attribute of the model, which should extend \Flarum\Database\AbstractModel.
* @param string $foreignKey: The foreign key attribute of the parent model.
* @param string $ownerKey: The primary key attribute of the parent model.
*/
public function belongsTo(string $name, $related, $foreignKey = null, $ownerKey = null)
{
return $this->relationship($name, function (AbstractModel $model) use ($related, $foreignKey, $ownerKey, $name) {
return $model->belongsTo($related, $foreignKey, $ownerKey, $name);
});
}
/**
* Establish a simple belongsToMany relationship from this model to another model.
* This represents a many-to-many relationship.
* For more complex relationships, use the ->relationship method.
*
* @param string $name: The name of the relation. This doesn't have to be anything in particular,
* but has to be unique from other relation names for this model, and should
* work as the name of a method.
* @param string $related: The ::class attribute of the model, which should extend \Flarum\Database\AbstractModel.
* @param string $table: The intermediate table for this relation
* @param string $foreignPivotKey: The foreign key attribute of the parent model.
* @param string $relatedPivotKey: The associated key attribute of the relation.
* @param string $parentKey: The key name of the parent model.
* @param string $relatedKey: The key name of the related model.
*/
public function belongsToMany(
string $name,
$related,
$table = null,
$foreignPivotKey = null,
$relatedPivotKey = null,
$parentKey = null,
$relatedKey = null
)
{
return $this->relationship($name, function (AbstractModel $model) use ($related, $table, $foreignPivotKey, $relatedPivotKey, $parentKey, $relatedKey, $name) {
return $model->belongsToMany($related, $table, $foreignPivotKey, $relatedPivotKey, $parentKey, $relatedKey, $name);
});
}
/**
* Establish a simple hasOne relationship from this model to another model.
* This represents a one-to-one relationship.
* For more complex relationships, use the ->relationship method.
*
* @param string $name: The name of the relation. This doesn't have to be anything in particular,
* but has to be unique from other relation names for this model, and should
* work as the name of a method.
* @param string $related: The ::class attribute of the model, which should extend \Flarum\Database\AbstractModel.
* @param string $foreignKey: The foreign key attribute of the parent model.
* @param string $localKey: The primary key attribute of the parent model.
*/
public function hasOne(string $name, $related, $foreignKey = null, $localKey = null)
{
return $this->relationship($name, function (AbstractModel $model) use ($related, $foreignKey, $localKey) {
return $model->hasOne($related, $foreignKey, $localKey);
});
}
/**
* Establish a simple hasMany relationship from this model to another model.
* This represents a one-to-many relationship.
* For more complex relationships, use the ->relationship method.
*
* @param string $name: The name of the relation. This doesn't have to be anything in particular,
* but has to be unique from other relation names for this model, and should
* work as the name of a method.
* @param string $related: The ::class attribute of the model, which should extend \Flarum\Database\AbstractModel.
* @param string $foreignKey: The foreign key attribute of the parent model.
* @param string $localKey: The primary key attribute of the parent model.
*/
public function hasMany(string $name, $related, $foreignKey = null, $localKey = null)
{
return $this->relationship($name, function (AbstractModel $model) use ($related, $foreignKey, $localKey) {
return $model->hasMany($related, $foreignKey, $localKey);
});
}
public function extend(Container $container, Extension $extension = null)
{
// Nothing needed here.
}
}