wpify/model

WPify 模型

4.1.16 2024-07-10 11:36 UTC

README

这个库提供了更好的 WordPress 数据访问方式。它是围绕 WordPress API 的包装,提供了一种更面向对象的数据访问方法。它还提供了一种定义自定义数据模型的方法,例如定义自定义文章类型、自定义分类或自定义数据库表的数据模型。

优点

  • 面向对象的数据访问。
  • 易于使用。
  • 易于扩展。
  • 易于定义和使用自定义表。
  • 最小化对数据库的查询次数。
  • 使用现代 PHP 8 功能,提供更好的开发者体验。

核心概念

该库使用了几种类型的对象

  • 模型:模型是一个包含一个实体数据的类,例如单个帖子、术语或表行。模型有明确定义的属性和方法来访问数据。
  • 仓库:仓库是一个提供数据访问的类。仓库可以从数据库、缓存或其他来源检索数据。
  • 管理器:管理器保存注册的模型和仓库列表。它还提供了一种通过名称检索模型或仓库的方法。

需求

  • PHP 8.0 或更高版本

安装

使用 composer 安装库

composer require wpify/model

基本用法

首先需要初始化管理器以访问内置模型和仓库

use Wpify\Model\Manager;

$manager = new Manager();

使用管理器,您可以使用内置模型和仓库。例如,要获取所有已发布的帖子,可以使用以下代码

$post_repository = $manager->get_repository( Wpify\Model\Post::class );
$posts           = $post_repository->find_published();

然后您可以通过模型访问数据

foreach ( $posts as $post ) {
    echo $post->title;
}

您还可以通过其 ID 或其他键检索单个帖子

$post = $post_repository->get( 123 );
$post = $post_repository->get( 'article-slug' );
$post = $post_repository->get( 'https://myblog.con/article-url/' );

更新模型

要更新数据,只需更新模型属性,然后通过在仓库上调用 save() 方法保存数据

$post->title = 'New title';

$post_repository->save( $post );

echo $post->title; // New title

创建新条目

要创建新条目,您需要通过仓库创建新的模型,然后保存它

$post = $post_repository->create( array(
    'title'   => 'New post',
    'content' => 'New content',
) );

$post_repository->save( $post );

echo $post->id; // 123

删除条目

要删除条目,需要在仓库上调用 delete() 方法

$post_repository->delete( $post );

自定义模型

您可以定义自己的模型以访问自定义文章类型、自定义分类或自定义数据库表中的数据。所有自定义模型都必须扩展 Wpify\Model\Model 类或其他模型。每个自定义模型都必须有一个仓库,该仓库必须扩展 Wpify\Model\Repository 类或其他仓库。

定义自定义模型

在此示例中,我们将定义一个具有一些元字段的自定义文章类型的模型

use Wpify\Model\Post;
use Wpify\Model\Attributes;

class Book extends Post {
    #[Attributes\Meta]
    public string $isbn;
    
    #[Attributes\Meta]
    public string $author;
}

所有属性都以 PHP 属性的形式进行定义。您可以使用以下属性

  • Attributes\AliasOf - 定义另一个属性的别名。
  • Attributes\AccessorObject - 定义从源对象获取的获取器和设置器。
  • Attributes\ChildPostRelation - 定义对子帖子的关系(仅适用于帖子模型)。
  • Attributes\ChildTermRelation - 定义对子术语的关系(仅适用于术语模型)。
  • Attributes\Column - 定义自定义表中的列(仅适用于自定义表模型)。
  • Attributes\IdsRelation - 通过 IDs 获取相关帖子。
  • Attributes\ManyToOneRelation - 通过外键模型的 ID 在另一个属性中检索相关模型。
  • Attributes\Meta - 定义元字段。
  • Attributes\OrderItemsRelation - 获取订单项。
  • Attributes\PostTermsRelation - 通过帖子ID获取相关术语。此属性还持久化帖子-术语关系。
  • Attributes\PostTermRelation - 通过帖子ID获取相关术语。此属性还持久化帖子-术语关系。请注意,如果帖子有多个术语,则只返回或持久化第一个。
  • Attributes\SourceObject - 为模型(例如 WP_Post 属性)定义源对象中的值。
  • Attributes\TermPostsRelation - 获取术语的相关帖子(仅适用于术语模型)。

还有一些属性可以修改属性的行为

  • Attributes\ReadOnlyProperty - 使属性只读。

一些属性有额外的参数,可以通过命名构造函数参数传递

#[Attributes\SourceObject( 'ID' )]
public int $id;

#[Attributes\Meta( '_isbn' )]
public string $isbn;

#[Attributes\Meta( meta_key: '_author' )]
public string $author;

#[Attributes\Column( type: Attributes\Column::VARCHAR, params: 1000, unique: true )]
public string $custom_column;

大多数属性都有默认值,因此您可以省略一些参数。

定义自定义存储库

要实际使用模型,您需要为它定义一个存储库。在此示例中,我们将为 Book 模型定义一个存储库

use Wpify\Model\PostRepository;

class BookRepository extends PostRepository {
    public function model() : string{
        return Book::class;
    }
    
    public function post_types() : array{
        array( 'book' );
    }
}

在创建存储库之后,您需要将其注册到管理器中

$manager->register_repository( BookRepository::class );

您还可以在管理器的构造函数中注册存储库

$manager = new Manager( new BookRepository() );

如果您使用 PHP-DI,则可以在容器中注册存储库

use DI;
use Wpify\Model\Manager;

$container_builder = new DI\ContainerBuilder();

$container_builder->addDefinitions( array(
	Manager::class => DI\create()->constructor(
		DI\get( BookRepository::class ),
	),
) );

$container = $container_builder->build();
$manager   = $container->get( Manager::class );
$book_repo = $manager->get_repository( BookRepository::class );

内置模型

该库提供了一些内置模型和存储库。您也可以通过扩展它们来定义自己的自定义模型。

  • PostPostRepository 用于帖子。
  • PagePageRepository 用于页面。
  • AttachmentAttachmentRepository 用于附件。
  • CategoryCategoryRepository 用于分类。
  • PostTagPostTagRepository 用于帖子标签。
  • UserUserRepository 用于用户。
  • CommentCommentRepository 用于评论。
  • UserUserRepository 用于用户。
  • MenuMenuRepository 用于菜单。
  • SiteSiteRepository 用于站点。
  • ProductProductRepository 用于 WooCommerce 产品。
  • OrderOrderRepository 用于 WooCommerce 订单。
  • OrderItemOrderItemRepository 用于 WooCommerce 订单项。
  • ProductCatProductCatRepository 用于 WooCommerce 产品分类。

自定义表模型

您可以创建和使用自定义表模型。为此,您需要为模型定义一个存储库和一个模型本身。表会自动创建,因此您不需要手动处理它,但您可以禁用此行为。

示例

class MyModelRepository extends CustomTableRepository {
  public function model(): string {
    return MyModel::class;
  }

  public function table_name(): string {
    return 'my_model';
  }
}

您还需要定义具有列属性的模型

class MyModel extends Model {
  #[Column( type: Column::INT, auto_increment: true, primary_key: true )]
  public int $id = 0;

  #[Column( type: Column::VARCHAR, params: 255 )]
  public string $name = '';
}

列属性接受以下参数

  • name:列的名称。如果未指定,则使用属性名称。
  • type:列的类型。如果未指定,则从属性类型推断类型。
  • params:列类型的参数。例如,对于 VARCHAR,您可以指定长度。
  • unsigned:列是否为无符号。默认为 false。
  • nullable:列是否为可空。默认为 false。
  • default:列的默认值。
  • on_update:更新时的列默认值。
  • auto_increment:列是否为自增。默认为 false。
  • primary_key:列是否为主键。默认为 false。
  • unique:列是否唯一。默认为 false。
  • foreign_key:设置外键的数据数组。

模型必须恰好包含一个主键列。

列可以是以下类型之一

  • Column::TINYINT (tinyint)
  • Column::INT (int)
  • Column::BIGINT (bigint)
  • Column::BOOLEAN (布尔值)
  • Column::DECIMAL (十进制)
  • Column::DATE (日期)
  • Column::DATETIME (日期时间)
  • Column::TIMESTAMP (时间戳)
  • Column::TIME (时间)
  • Column::CHAR (字符)
  • Column::VARCHAR (可变长度字符)
  • Column::BLOB (二进制大对象)
  • Column::TEXT (文本)
  • Column::ENUM (枚举)
  • Column::SET (集合)
  • Column::JSON (JSON)

外键数组包含以下项

  • Column::FOREIGN_TABLE:不带 WP 前缀的外表名称(例如 posts)。
  • Column::FOREIGN_COLUMN:外键列名称(例如 ID)。
  • Column::FOREIGN_SETTINGS:可选设置,例如 ON DELETE CASCADE

当使用存储库时,存储库将自动创建表。如果您想禁用自动迁移,可以在构造函数中将 auto_migrate 参数传递为 false。然后您可以在适当的位置手动调用 migrate() 方法进行迁移,例如插件激活钩子、admin_init 钩子等。

$repository = new MyModelRepository( auto_migrate: false );

$manager->register_repository( $repository );

add_action( 'admin_init', array( $repository, 'migrate' ) );

表名将自动添加 WordPress 表前缀。如果您想禁用此功能,可以在构造函数中将 use_prefix 参数传递为 false

$repository = new MyModelRepository( use_prefix: false );

$manager->register_repository( $repository );

如果您想删除数据库表,可以调用 drop_table() 方法。这在卸载插件时很有用。

$repository = new MyModelRepository();

$manager->register_repository( $repository );

register_uninstall_hook( $main_php_file_path, array( $repository, 'drop_table' ) );

查询自定义表

您可以使用查找函数查询自定义表

$items = $repository->find( array(
  'where' => "name = '" . esc_sql( 'Alex' ) . "'",
) );

即使这可行,也不建议使用此方法,因为它容易受到 SQL 注入的攻击。相反,您应该使用数组作为参数,它将清理值,并且您可以执行复杂的查询

$items = $repository->find( array(
    array(
        'table.col0 <>' => true,
        'OR',
        'table.col1' => true,
        'or',
        array(
            'table.col2' => 'active',
            'table.col3 <>' => 'active'
        )
    ),
    'table.col4' => array( 1, 2, 3 ),
    'table.col5 NOT IN' => array( 'test', 'test2', 'test3' ),
    'table.col6 BETWEEN 1 AND 10',
    'table.col7 BETWEEN' => array( 1, 10 ),
    'EXISTS' => 'SELECT * FROM table2 WHERE table.id = table2.table_id',
) );

如您所见,您甚至可以使用嵌套查询或在键中指定运算符。您还可以定义是否使用 OR 或 AND 运算符。

待办事项

  • 生成文档
  • 添加测试
  • 自定义表 - 缓存、元数据
  • 实现其他 WooCommerce 模型
    • VariableProduct
    • SimpleProduct
    • GroupedProduct
    • ExternalProduct
    • DownloadableProduct
    • ProductTag
    • ProductAttribute
    • ProductVariation
    • ShopCoupon
    • ShopWebhook
  • 实现 WooCommerce 订阅模型
  • 实现 SQL 查询模型