idetik / coretik

该软件包最新版本(v1.9.2)没有可用的许可信息。

Idetik WP 主题核心


README

Latest Stable Version License

Coretik:WordPress 框架

管理模型、查询、服务等...

安装

composer require idetik/coretik

开始使用

依赖注入容器

Coretik 应用使用 Pimple 作为依赖注入容器。与其他依赖注入容器类似,Pimple 管理两种不同类型的数据:服务和参数。请阅读 Github 上的官方文档:https://github.com/silexphp/Pimple。Coretik 随带几个内置服务。您可以在 src/Services 中找到它们(在 todoux 列表中有文档...)

首先,在您的 functions.php 中创建应用程序容器

use Coretik\App;
use Coretik\Core\Container;

$container = new Container();

$container['my-service'] = function ($container) {
    return new MyService();
};

App::run($container);

模式:声明自定义帖子类型和分类法

简单用例

use Coretik\Core\Builders\Taxonomy;
use Coretik\Core\Builders\PostType;

// Declare post type
PostType::make('my_custom_post_type')
    ->setSingularName('Title')
    ->setPluralName('Titles')
    ->addToSchema();

// Declare taxonomy
Taxonomy::make('my_taxonomy')
    ->setSingularName('Title')
    ->setPluralName('Titles')
    ->for('my_custom_post_type')
    ->addToSchema();

高级

这是一个高级用例,使用 模型查询处理器

帖子类型
use Coretik\Core\Builders\Taxonomy;

use App\Model\MyModel;
use App\Query\MyQuery;
use App\Handler\MyHandlerA;
use App\Handler\MyHandlerB;

// Accept same arguments as register_post_type() (https://developer.wordpress.org/reference/functions/register_post_type/) and register_extended_post_type() (https://github.com/johnbillion/extended-cpts/wiki/Registering-Post-Types)
$register_extended_post_type_args = [];

PostType::make('my_custom_post_type')
    ->setSingularName('Title')
    ->setPluralName('Titles')
    ->setArgs($register_extended_post_type_args) // Optional, 
    ->factory(MyModel::class) // Optional, you can add a custom model factory or use the default factory built in Coretik 
    ->querier(MyQuery::class) // Optional, you can add a custom query class or use the default querier built in Coretik
    ->handler(MyHandlerA::class) // Optional, you can use many handlers on the same builder
    ->handler(MyHandlerB::class)
    ->attach('myMacroA', 'my_callable') // Optional, you can attach all callables you want
    ->attach('myMacroB', 'my_callable')
    ->addToSchema();
分类法
use Coretik\Core\Builders\Taxonomy;

use App\Model\MyTermModel;
use App\Query\MyTermQuery;
use App\Handler\MyTermHandlerA;
use App\Handler\MyTermHandlerB;

// Accept same arguments as register_taxonomy() (https://developer.wordpress.org/reference/functions/register_taxonomy/) and register_extended_taxonomy() (https://github.com/johnbillion/extended-cpts/wiki/Registering-taxonomies)
$register_extended_taxonomy_args = [];

Taxonomy::make('my_custom_taxonomy')
    ->setSingularName('Title')
    ->setPluralName('Titles')
    ->setArgs($register_extended_taxonomy_args) // Optional, 
    ->factory(MyTermModel::class) // Optional, you can add a custom model factory or use the default factory built in Coretik 
    ->querier(MyTermQuery::class) // Optional, you can add a custom query class or use the default querier built in Coretik
    ->handler(MyTermHandlerA::class) // Optional, you can use many handlers on the same builder
    ->handler(MyTermHandlerB::class)
    ->attach('myMacroA', 'my_callable') // Optional, you can attach all callables you want
    ->attach('myMacroB', 'my_callable')
    ->addToSchema();

模型

作为 MVC 设计模式中的模型,它只包含纯应用数据。这使得随着时间的推移更容易维护和扩展应用程序。它支持帖子类型和分类法或其他自定义内容之间的关联。

设置

use Coretik\Core\Models\Wp\PostModel;

class MyPostModel extends PostModel
{
    public function foo()
    {
        return 'bar';
    }
}

$postSchema = app()->schema('post');
$postSchema->factory(MyPostModel::class);

用法

$models = app()->schema('post')->query()->models();

foreach ($models as $model) {
    echo $model->foo(); // 'bar'
}

高级

模型可以轻松处理帖子元数据,包括受保护的元数据。模型提供了类似对象属性的元访问器。元数据必须在模型构造函数中声明。仅在 CRUD 操作中声明的元数据才会被保存到数据库中。

use Coretik\Core\Models\Wp\PostModel;
use Coretik\Core\Models\Interfaces\ModelInterface;
use Coretik\Core\Collection;

class MyPostModel extends PostModel
{
    protected function intializeModel(): void
    {
        $this->declareMetas([
            'ma_meta_a' => 'bdd_field_name',
            'ma_meta_b' => 'other_bdd_field_name',
        ]);

        // Each meta
        // @see Core/Models/MetaDefinition.php
        $this->metaDefinition('ma_meta_a')->castTo('array');
        $this->metaDefinition('ma_meta_b')->protectWith(fn ($model) => (bool)$model->canIUpdateThisValue());
    }

    public function canIUpdateThisValue(): bool
    {
        // @todo create a guard
        return true;
    }

    public function foo(): string
    {
        if (in_array('bar', $this->get('ma_meta_a'))) {
            return 'bar';
        }

        return 'foo';
    }

    /**
     * Accessor
     * 
     * To define an accessor, create a getFooAttribute method on your model where Foo is the "studly" cased name of the column you wish to access.
     * In this example, we'll define an accessor for the first_name attribute. The accessor will automatically be called when attempting to retrieve the value of the first_name attribute:
     */
    public function getFirstNameAttribute(): string
    {
        if (empty($this->get('ma_meta_b'))) {
            return 'toto';
        }
        
        return $this->get('ma_meta_b');
    }

    /**
     * Mutator
     * 
     * To define a mutator, define a setFooAttribute method on your model where Foo is the "studly" cased name of the column you wish to access.
     * So, again, let's define a mutator for the first_name attribute. This mutator will be automatically called when we attempt to set the value of the first_name attribute on the model:
     */
    public function setFirstNameAttribute($value)
    {
        $this->ma_meta_b = strtolower($value);
    }

    /**
     * Relationships
     * 
     * For now, only post <-> taxonomy relationships are ready to use with wp-admin.
     * Posts to posts relationships (1, n) require an extra handler on the post type builder, who update the post_parent column on save post.
     * We are working to include this feature on a next release.
     */
    public function setCategory(ModelInterface|int|string $category): self
    {
        $current = $this->category();
        if (!empty($current)) {
            $this->detachTerm($current, 'my_category_taxonomy');
        }
        $this->setTerm($category, 'my_category_taxonomy');
        return $this;
    }

    public function category(): ?ModelInterface
    {
        return $this->hasOne('my_category_taxonomy');
    }

    public function setAttributes(array $attributes): self
    {
        $this->attributes()->each(fn ($attribute) => $this->detachTerm($attribute, 'my_attributes_taxonomy'));
        $this->attributes = [];
        foreach ($attributes as $attr) {
            $this->setTerm($attribute, 'my_attributes_taxonomy');
        }
        return $this;
    }

    public function attributes(): Collection
    {
        return $this->hasMany('my_attributes_taxonomy');
    }

    public function addToGroup(int $post_group_id): self
    {
        $this->post_parent = $group_id;
        return $this;
    }

    public function group(): ?ModelInterface
    {
        return $this->belongsTo('my_post_type_group'); // require an extra handler
    }
}

$postSchema = app()->schema('my_custom_post_type');
$postSchema->factory(MyPostModel::class);

创建并保存模型

$model = app()->schema('my_custom_post_type')->model();
$model->post_title = 'Mr Bar Foo';
$model->post_status = 'publish';
$model->ma_meta_a = 'Foo';
$model->first_name = 'Bar';
$model->setAttributes(['smart', 'tall']);
$model->addToGroup(100); // a post with title 'Groupe 1' from 'my_post_type_group' with ID 100, 
$model->save();

$modelId = $model->id();

使用模型

$myModel = app()->schema('my_custom_post_type')->model($modelId);

echo $myModel->foo(); // foo
echo $myModel->ma_meta_a; // ['Foo']
echo $myModel->first_name; // bar
echo $myModel->ma_meta_b; // bar
echo $myModel->group()->title(); // Groupe 1
$myModel->attributes()->each(fn ($attributeModel) => echo $attributeModel->title() . ', '); // smart, tall, 

查询

使用 Coretik 查询检索复杂子句后面的模型。查询比需要直接管理元数据、分类法和设置的基wp_query 更易于阅读和使用。有四种类型的查询可供使用:PostQuery、TermQuery、UserQuery 和 CommentQuery。

简单查询

查询所有通过默认查询参数过滤的 wp_post 的方法,并浏览结果模型

src/Core/Query/Post::getQueryArgsDefault()

$models = app()->schema('my_custom_post_type')->query()->models();

foreach ($models as $model) {
    echo $model->title();
}

其他查询

src/Core/Query/Adapters 文件夹。

自定义查询

设置

use Coretik\Core\Query\Post as PostQuery;
use Coretik\Core\Models\Interfaces\ModelInterface;

class MyPostQuery enxtends PostQuery
{
    public function myCustomFilter(): self
    {
        $this->set([...]);
        $this->whereMeta([...]);
        $this->whereTax([...]);
        return $this;
    }

    public function ordered(): self
    {
        $this->set('orderby', 'menu_order title');
        $this->set('order', 'ASC');
        return $this;
    }

    public function category(int $category): self
    {
        $this->whereTax('my_taxonomy', $category);
        return $this;
    }

    public function inGroup(int $group_id): self
    {
        $this->set('post_parent', $group_id);
        return $this;
    }

    public function withAttribute(string $attribute): self
    {
        $this->whereTax('my_attributes_taxonomy', $attribute, 'IN', 'slug');
        return $this;
    }
}

$postSchema = app()->schema('my_custom_post_type');
$postSchema->querier(MyPostQuery::class);

用法

$result = app()
            ->schema('my_custom_post_type')
                ->query()
                    ->ordered()
                    ->inGroup(100)
                    ->withAttribute('smart')
                        ->or('small')
                    ->whereMeta('ma_meta_b', 'bar')
                    ->first();

echo $result->title(); // Mr Bar Foo

处理器

处理器旨在可重用、可维护和灵活。处理器允许我们挂钩帖子类型或分类法相关的任何内容,并允许我们根据需要修改默认工作流程。

您的处理器必须实现 Coretik\Core\Builders\Interfaces\HandlerInterface;

让我们以一个应用程序为例,该应用程序有许多属于分类的培训。每个培训有许多属于同一分类的事件。我们有一个培训帖子类型、一个事件帖子类型和一个分类法。我想在更改培训分类时更新事件分类。

use Coretik\Core\Builders\Interfaces\HandlerInterface;
use Coretik\Core\Builders\Interfaces\HandlerInterface;

/**
 * Reset session domain on formation saving
 */
class FormationCategoryOnChangeHandler implements HandlerInterface
{
    private $builder;

    public function handle(BuilderInterface $builder): void
    {
        $this->builder = $builder;
        \add_action('set_object_terms', [$this, 'setEventsCategory'], 10, 6);
    }

    public function freeze(): void
    {
        \remove_action('set_object_terms', [$this, 'setEventsCategory'], 10, 6);
    }

    public function setEventsCategory($object_id, $terms, $tt_ids, $taxonomy, $append, $old_tt_ids)
    {
        // Ensure current post editing belongs to our builder
        if (!$this->builder->concern((int)$object_id)) {
            return;
        }

        // Bypass if any diff about terms after save (You have to verify the taxonomy name if many taxonomies exist)
        if (empty(\array_diff($tt_ids, $old_tt_ids))) {
            return;
        }

        $model = $this->builder->model((int)$object_id);
        $model->events()->each(fn ($event) => $event->setCategories($tt_ids)->save());
    }
}

用于扩展构建器。

PostType::make('my_custom_post_type')
    ->setSingularName('Title')
    ->setPluralName('Titles')
    ->attach('myMacroA', fn ($input) => 'my_custom_post_type : ' . $input) // Optional, you can attach all callables you want
    ->addToSchema();

echo app()->schema('my_custom_post_type')->myMacroA('foo'); // my_custom_post_type : foo