kphoen / doctrine-state-machine-bundle

此包已弃用,不再维护。未建议替代包。

将 DoctrineStateMachineBehavior 集成到 Symfony2 中。

安装次数: 217,452

依赖者: 0

建议者: 0

安全: 0

星标: 48

关注者: 3

分支: 19

开放问题: 7

类型:symfony-bundle

1.1.3 2016-08-17 08:28 UTC

This package is auto-updated.

Last update: 2022-02-01 12:27:45 UTC


README

为实体添加有限状态机的 Doctrine2 行为。

使用的状态机实现是 Finite

状态

此项目已 弃用,不应使用。

如果有人出现并希望维护此项目,我将乐意提供对仓库的访问权限。

配置

在您的 app/config/config.yml 文件中,定义您的状态机

k_phoen_doctrine_state_machine:
    auto_injection:     true    # should we automatically inject state machines into hydrated objects?
    auto_validation:    true    # should we validate any status change before the persistence happens?

    state_machines:
        article_state_machine:
            class:      \Acme\FooBundle\Entity\Article
            property:   state
            states:
                new:        {type: initial}
                reviewed:   ~
                accepted:   ~
                published:  {type: final, properties: {printable: true}}
                rejected:   {type: final}
            transitions:
                review:     {from: [new], to: reviewed}
                accept:     {from: [reviewed], to: accepted}
                publish:    {from: [accepted], to: published}
                reject:     {from: [new, reviewed, accepted, published], to: rejected}

状态机配置非常简单。除了状态和转换,您还需要定义实体类和用于存储状态的列。

重要:实体必须 实现 Stateful 接口

为了简化实现,您可以使用行为附带的自定义 StatefulTrait

使用

Stateful 实体可以访问它们自己的状态机。有关详细信息,请参阅 Finite 的文档

以下 Article 实体已准备好作为 Stateful 实体使用。

<?php

namespace Acme\FooBundle\Entity;

use KPhoen\DoctrineStateMachineBehavior\Entity\Stateful;
use KPhoen\DoctrineStateMachineBehavior\Entity\StatefulTrait;

class Article implements Stateful
{
    use StatefulTrait;

    /**
     * define your fields here
     */


    /**
     * @var string
     */
    protected $state = 'new';

    /**
     * Set state
     *
     * @param  string  $state
     * @return Article
     */
    public function setState($state)
    {
        $this->state = $state;

        return $this;
    }

    /**
     * Get state
     *
     * @return string
     */
    public function getState()
    {
        return $this->state;
    }

    /**
     * Sets the object state.
     * Used by the StateMachine behavior
     *
     * @return string
     */
    public function getFiniteState()
    {
        return $this->getState();
    }

    /**
     * Sets the object state.
     * Used by the StateMachine behavior
     *
     * @param string $state
     */
    public function setFiniteState($state)
    {
        return $this->setState($state);
    }
}

使用 StatefulTrait 的实体将看到实现了的 setStateMachine()getStateMachine() 方法,并获得以下方法的访问权限

  • can($transition):表示是否允许给定的转换;
  • 以及一些基于状态机允许的转换的魔法方法
    • {TransitionName}():应用转换 {TransitionName}(例如:accept()reject() 等);
    • can{TransitionName}():测试转换 {TransitionName} 是否可以应用(例如:canAccept()canReject() 等)。
    • is{StateName}():测试当前状态是否为 {StateName}(例如:isAccepted()isRejected() 等)。
<?php

$article = new Article();

$article->canAccept();
$article->canReject();
$article->can('accept');

$article->accept();
$article->publish();

$article->isAccepted();
$article->isRejected();

生命周期回调

如果您使用的是具有事件感知状态机的扩展(这是此包默认使用的),则扩展提供了为具有状态的实体实现“生命周期回调”的监听器。

对于每个可用的转换,可以执行三个方法

  • pre{TransitionName}():在应用转换 {TransitionName} 之前调用;
  • post{TransitionName}():在应用转换 {TransitionName} 之后调用;
  • can{TransitionName}():当状态机测试转换 {TransitionName} 是否可以应用时调用。
<?php

namespace Acme\FooBundle\Entity;

use KPhoen\DoctrineStateMachineBehavior\Entity\Stateful;
use KPhoen\DoctrineStateMachineBehavior\Entity\StatefulTrait;

class Article implements Stateful
{
    // previous code

    public function preAccept()
    {
        // your logic here
    }

    public function postAccept()
    {
        // your logic here
    }

    public function onCanAccept()
    {
        // your logic here
    }
}

使用服务

您可以使用 Finite 事件上的监听器将状态逻辑放在实体之外。此扩展提供具有与“生命周期回调”监听器相同方法的抽象事件订阅者。

您需要声明一个服务和扩展 AbstractSubscriber。

services:
    article_workflow_subscriber:
        class: Acme\FooBundle\Workflow\ArticleSubscriber
        tags:
            - { name: kernel.event_subscriber }
<?php

namespace Acme\FooBundle\Workflow;

use KPhoen\DoctrineStateMachineBundle\Listener\AbstractSubscriber;

class ArticleSubscriber extends AbstractSubscriber
{
    public function supportsObject($object)
    {
        return $object instanceof \Acme\FooBundle\Entity\Article;
    }

    public function preAccept()
    {
        // your logic here
    }

    public function postAccept()
    {
        // your logic here
    }

    public function canAccept()
    {
        // your logic here
    }
}

Twig

该捆绑包还公开了一些Twig助手

{# your template ... #}

{% if article|can('reject') %}
    <a class="btn btn-danger" href="{{ path('article_delete', article) }}">
        <i class="icon-trash"></i>
        {{ 'link_reject'|trans }}
    </a>
{% endif %}

{# this is strictly equivalent #}
{% if can(article, 'reject') %}
    <a class="btn btn-danger" href="{{ path('article_delete', article) }}">
        <i class="icon-trash"></i>
        {{ 'link_reject'|trans }}
    </a>
{% endif %}

{% if current_state(article).isFinal %}
    blabla
{% endif %}

{% if article|is_status('rejected') %}
    blabla
{% endif %}

{# this is strictly equivalent #}
{% if is_status(article, 'rejected') %}
    blabla
{% endif %}

{% if article|has_property('printable') %}
    {{ article|property('printable') ? 'I can print' : 'I CANNOT print' }}
{% endif %}

{# this is strictly equivalent #}
{% if has_property(article, 'printable') %}
    {{ property(article, 'printable') ? 'I can print' : 'I CANNOT print' }}
{% endif %}

安装

安装行为,将kphoen/doctrine-state-machine-bundle添加到您的composer.json或从CLI安装

composer require kphoen/doctrine-state-machine-bundle

然后在您的app/AppKernel.php文件中注册该捆绑包

// app/AppKernel.php
public function registerBundles()
{
    $bundles = array(
        // ...
        new KPhoen\DoctrineStateMachineBundle\KPhoenDoctrineStateMachineBundle(),
        // ...
    );
}

许可证

此捆绑包在MIT许可证下发布。