stellarwp / models
一个简单模型结构的库。
Requires
- stellarwp/db: ^1.0.3
Requires (Dev)
- codeception/module-asserts: ^1.0
- codeception/module-cli: ^1.0
- codeception/module-db: ^1.0
- codeception/module-filesystem: ^1.0
- codeception/module-phpbrowser: ^1.0
- codeception/module-rest: ^1.0
- codeception/module-webdriver: ^1.0
- codeception/util-universalframework: ^1.0
- lucatume/wp-browser: ^3.0.14
- phpunit/phpunit: ~6.0
This package is auto-updated.
Last update: 2024-09-09 15:26:52 UTC
README
一个简单模型结构的库。
目录
安装
建议通过 Composer 将 Schema 作为项目依赖项安装
composer require stellarwp/models
我们实际上建议使用 Strauss 将此库包含在您的项目中。
幸运的是,将 Strauss 添加到您的
composer.json
的复杂性仅略高于添加典型依赖项,所以请查看我们的 strauss 文档。
示例说明
由于建议使用 Strauss 为此库的命名空间添加前缀,所有示例都将使用 Boomshakalaka
命名空间前缀。
配置
在此库的类可以使用之前,需要对其进行一些配置。配置通过 Config
类完成。
use Boomshakalaka\StellarWP\Models\Config; add_action( 'plugins_loaded', function() { Config::setHookPrefix( 'boom-shakalaka' ); } );
创建模型
模型是包含数据并提供与该数据交互的一些辅助方法的类。
简单的模型
这是一个仅持有属性的模型示例。
namespace Boomshakalaka\Whatever; use Boomshakalaka\StellarWP\Models\Model; class Breakfast_Model extends Model { /** * @inheritDoc */ protected $properties = [ 'id' => 'int', 'name' => 'string', 'price' => 'float', 'num_eggs' => 'int', 'has_bacon' => 'bool', ]; }
只读模型
这是一个仅读取和存储数据的模型。在大多数情况下,读取操作应委托给仓库类,但模型应提供一个简单的接口来与仓库交互。您可以通过实现 Contracts\ModelReadOnly
契约创建只读模型。
namespace Boomshakalaka\Whatever; use Boomshakalaka\StellarWP\Models\Contracts; use Boomshakalaka\StellarWP\Models\Model; use Boomshakalaka\StellarWP\Models\ModelQueryBuilder; class Breakfast_Model extends Model implements Contracts\ModelReadOnly { /** * @inheritDoc */ protected $properties = [ 'id' => 'int', 'name' => 'string', 'price' => 'float', 'num_eggs' => 'int', 'has_bacon' => 'bool', ]; /** * @inheritDoc */ public static function find( $id ) : Model { return App::get( Repository::class )->get_by_id( $id ); } /** * @inheritDoc */ public static function query() : ModelQueryBuilder { return App::get( Repository::class )->prepare_query(); } }
CRUD 模型
这是一个包含 CRUD 操作的模型。理想情况下,实际的 CRUD 操作应委托给并由仓库类处理,但模型应提供一个简单的接口来与仓库交互。我们通过实现 Contracts\ModelCrud
契约获得 CRUD 模型。
namespace Boomshakalaka\Whatever; use Boomshakalaka\StellarWP\Models\Contracts; use Boomshakalaka\StellarWP\Models\Model; use Boomshakalaka\StellarWP\Models\ModelQueryBuilder; class Breakfast_Model extends Model implements Contracts\ModelCrud { /** * @inheritDoc */ protected $properties = [ 'id' => 'int', 'name' => 'string', 'price' => 'float', 'num_eggs' => 'int', 'has_bacon' => 'bool', ]; /** * @inheritDoc */ public static function create( array $attributes ) : Model { $obj = new static( $attributes ); return App::get( Repository::class )->insert( $obj ); } /** * @inheritDoc */ public static function find( $id ) : Model { return App::get( Repository::class )->get_by_id( $id ); } /** * @inheritDoc */ public function save() : Model { return App::get( Repository::class )->update( $this ); } /** * @inheritDoc */ public function delete() : bool { return App::get( Repository::class )->delete( $this ); } /** * @inheritDoc */ public static function query() : ModelQueryBuilder { return App::get( Repository::class )->prepareQuery(); } }
属性验证
有时验证在模型中设置的属性可能会有所帮助。为此,您可以创建 validate_*()
方法,该方法将在设置任何属性时执行。
以下是一个示例
namespace Boomshakalaka\Whatever; use Boomshakalaka\StellarWP\Models\Model; class Breakfast_Model extends Model { /** * @inheritDoc */ protected $properties = [ 'id' => 'int', 'name' => 'string', 'price' => 'float', 'num_eggs' => 'int', 'has_bacon' => 'bool', ]; /** * Validate the name. * * @param string $value * * @return bool */ public function validate_name( $value ): bool { if ( ! preg_match( '/eggs/i', $value ) ) { throw new \Exception( 'Breakfasts must have "eggs" in the name!' ); } return true; } }
数据传输对象
数据传输对象(DTO)是帮助将数据库查询结果(或其他数据源)转换为模型的类。DTO 不是使用此库的必需品,但它们是推荐的。使用这些对象可以帮助您更谨慎地使用查询,并允许模型和仓库与 ModelQueryBuilder
良好地协作。
以下是一个早餐 DTO 的示例
namespace Boomshakalaka\Whatever; use Boomshakalaka\Whatever\StellarWP\Models\DataTransferObject; use Boomshakalaka\Whatever\Breakfast_Model; class Breakfast_DTO extends DataTransferObject { /** * Breakfast ID. * * @var int */ public int $id; /** * Breakfast name. * * @var string */ public string $name; /** * Breakfast price. * * @var float */ public float $price; /** * Number of eggs in the breakfast. * * @var int */ public int $num_eggs; /** * Whether or not the breakfast has bacon. * * @var bool */ public bool $has_bacon; /** * Builds a new DTO from an object. * * @since TBD * * @param object $object The object to build the DTO from. * * @return Breakfast_DTO The DTO instance. */ public static function fromObject( $object ): self { $self = new self(); $self->id = $object->id; $self->name = $object->name; $self->price = $object->price; $self->num_eggs = $object->num_eggs; $self->has_bacon = (bool) $object->has_bacon; return $self; } /** * Builds a model instance from the DTO. * * @since TBD * * @return Breakfast_Model The model instance. */ public function toModel(): Breakfast_Model { $attributes = get_object_vars( $this ); return new Breakfast_Model( $attributes ); } }
仓库
仓库是从数据库中检索并与之交互的类。理想情况下,仓库应用于以不同方式查询数据库并返回相应的模型。使用此库时,我们提供了 Deletable
、Insertable
和 Updatable
契约,可用于指示仓库提供的操作。
你可能想知道为什么没有Findable
或Readable
合约(或类似)。这是因为仓库的获取需求会根据用例而变化。然而,在Repository
抽象类中,有一个抽象的prepareQuery()
方法。这个方法应该返回一个可以用来从数据库中获取数据的ModelQueryBuilder
实例。
namespace Boomshakalaka\Whatever; use Boomshakalaka\StellarWP\Models\Contracts\Model; use Boomshakalaka\StellarWP\Models\ModelQueryBuilder; use Boomshakalaka\StellarWP\Repositories\Repository; use Boomshakalaka\StellarWP\Repositories\Contracts; use Boomshakalaka\Whatever\Breakfast_Model; use Boomshakalaka\Whatever\Breakfast as Table; class Breakfast_Repository extends Repository implements Contracts\Deletable, Contracts\Insertable, Contracts\Updatable { /** * {@inheritDoc} */ public function delete( Model $model ): bool { return (bool) DB::delete( Table::table_name(), [ 'id' => $model->id ], [ '%d' ] ); } /** * {@inheritDoc} */ public function insert( Model $model ): Breakfast_Model { DB::insert( Table::table_name(), [ 'name' => $model->name, 'price' => $model->price, 'num_eggs' => $model->num_eggs, 'has_bacon' => (int) $model->has_bacon, ], [ '%s', '%s', '%d', '%d', ] ); $model->id = DB::last_insert_id(); return $model; } /** * {@inheritDoc} */ function prepareQuery(): ModelQueryBuilder { $builder = new ModelQueryBuilder( Breakfast_Model::class ); return $builder->from( Table::table_name( false ) ); } /** * {@inheritDoc} */ public function update( Model $model ): Model { DB::update( Table::table_name(), [ 'name' => $model->name, 'price' => $model->price, 'num_eggs' => $model->num_eggs, 'has_bacon' => (int) $model->has_bacon, ], [ 'id' => $model->id ], [ '%s', '%s', '%d', '%d', ], [ '%d' ] ); return $model; } /** * Finds a Breakfast by its ID. * * @since TBD * * @param int $id The ID of the Breakfast to find. * * @return Breakfast_Model|null The Breakfast model instance, or null if not found. */ public function find_by_id( int $id ): ?Breakfast_Model { return $this->prepareQuery()->where( 'id', $id )->get(); } }
与仓库交互
查询
$breakfast = App::get( Breakfast_Repository::class )->find_by_id( 1 ); // Or, we can fetch via the model, which defers to the repository. $breakfast = Breakfast_Model::find( 1 );
插入
$breakfast = new Breakfast_Model( [ 'name' => 'Bacon and Eggs', 'price' => 5.99, 'num_eggs' => 2, 'has_bacon' => true, ] ); $breakfast->save();
更新
$breakfast = Breakfast_Model::find( 1 ); $breakfast->setAttribute( 'price', 6.99 ); $breakfast->save();
删除
$breakfast = Breakfast_Model::find( 1 ); $breakfast->delete();
值得注意的类
Model
这是一个抽象类,用于扩展你的模型。
ModelFactory
这是一个抽象类,用于扩展以创建模型工厂。
ModelQueryBuilder
该类扩展了stellarwp/db
的QueryBuilder
类,使其返回模型实例而不是数组或stdClass
实例。使用此功能需要实现ModelFromQueryBuilderObject
接口的模型。
DataTransferObject
这是一个用于扩展你的DTOs的抽象类。
Repositories\Repository
这是一个用于扩展你的仓库的抽象类。
值得注意的契约
Contracts\ModelCrud
在模型中提供CRUD操作的方法定义。
Contracts\ModelHasFactory
在模型中提供工厂方法的定义。
Contracts\ModelReadOnly
在模型中提供读取操作的方法签名。
Repositories\Contracts\Deletable
在仓库中提供删除方法的方法签名。
Repositories\Contracts\Insertable
在仓库中提供插入方法的方法签名。
Repositories\Contracts\Updatable
在仓库中提供更新方法的方法签名。