支付宝扫一扫付款
微信扫一扫付款
(微信为保护隐私,不显示你的昵称)
工作流组件提供了一个面向对象的方式,来定义你的对象所经历的进程或生命周期。进程中的每一步,或每一个阶段,被称之为一个 place(位置)。你还必须定义 transitions(过渡)来描述从一个位置到另一个位置时的action(动作)。
一组位置及其过渡,创建了一个 definition(定义)。一个工作流,需要的是一个 Definition
以及把状态(state)写入对象实例 (如,一个 MarkingStoreInterface
实例) 的方式。
思考以下博客主题的例程。每篇主题可以有一个预定义状态(predefined status,比如草稿、审稿、拒发、已发)的编号。你可以像这样定义这个工作流:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | framework:
workflows:
blog_publishing:
type: 'workflow' # or 'state_machine'
marking_store:
type: 'multiple_state' # or 'single_state'
arguments:
- 'currentPlace'
supports:
- AppBundle\Entity\BlogPost
places:
- draft
- review
- rejected
- published
transitions:
to_review:
from: draft
to: review
publish:
from: review
to: published
reject:
from: review
to: rejected |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | <!-- app/config/config.xml -->
<?xml version="1.0" encoding="utf-8" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:framework="http://symfony.com/schema/dic/symfony"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd
http://symfony.com/schema/dic/symfony http://symfony.com/schema/dic/symfony/symfony-1.0.xsd"
>
<framework:config>
<framework:workflow name="blog_publishing" type="workflow">
<framework:marking-store type="single_state">
<framework:arguments>currentPlace</framework:arguments>
</framework:marking-store>
<framework:support>AppBundle\Entity\BlogPost</framework:support>
<framework:place>draft</framework:place>
<framework:place>review</framework:place>
<framework:place>rejected</framework:place>
<framework:place>published</framework:place>
<framework:transition name="to_review">
<framework:from>draft</framework:from>
<framework:to>review</framework:to>
</framework:transition>
<framework:transition name="publish">
<framework:from>review</framework:from>
<framework:to>published</framework:to>
</framework:transition>
<framework:transition name="reject">
<framework:from>review</framework:from>
<framework:to>rejected</framework:to>
</framework:transition>
</framework:workflow>
</framework:config>
</container> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | // app/config/config.php
$container->loadFromExtension('framework', array(
// ...
'workflows' => array(
'blog_publishing' => array(
'type' => 'workflow', // or 'state_machine'
'marking_store' => array(
'type' => 'multiple_state', // or 'single_state'
'arguments' => array('currentPlace')
),
'supports' => array('AppBundle\Entity\BlogPost'),
'places' => array(
'draft',
'review',
'rejected',
'published',
),
'transitions' => array(
'to_review'=> array(
'form' => 'draft',
'to' => 'review',
),
'publish'=> array(
'form' => 'review',
'to' => 'published',
),
'reject'=> array(
'form' => 'review',
'to' => 'rejected',
),
),
),
),
)); |
1 2 3 4 5 6 7 8 | class BlogPost
{
// This property is used by the marking store
// 此属性被marking stroe所用
public $currentPlace;
public $title;
public $content
} |
marking store的类型可以是 "multiple_state" 或 "single_state"。一个单一的state marking store不支持模型在同一时间出现在多个place(位置)。
使用这个名为 blog_publishing
的工作流,你可以得到 “决定对博客主题进行何种操作” 的帮助。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | $post = new \AppBundle\Entity\BlogPost();
$workflow = $this->container->get('workflow.blog_publishing');
$workflow->can($post, 'publish'); // False
$workflow->can($post, 'to_review'); // True
// Update the currentState on the post
// 更新主题的当前状态
try {
$workflow->apply($post, 'to_review');
} catch (LogicException $e) {
// ...
}
// See all the available transition for the post in the current state
// 查看主题在当前状态下全部可用的过渡
$transitions = $workflow->getEnabledTransitions($post); |
要让你的工作流更加强大,你应该在构建 Workflow
对象时使用一个 EventDispatcher
。你现在可以创建监听来阻止过渡(如,根据博客主题中的数据)。以下事件会被派遣:
workflow.guard
workflow.[workflow name].guard
workflow.[workflow name].guard.[transition name]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | use Symfony\Component\Workflow\Event\GuardEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
class BlogPostReviewListener implements EventSubscriberInterface
{
public function guardReview(GuardEvent $event)
{
/** @var Acme\BlogPost $post */
$post = $event->getSubject();
$title = $post->title;
if (empty($title)) {
// Posts with no title should not be allowed
$event->setBlocked(true);
}
}
public static function getSubscribedEvents()
{
return array(
'workflow.blogpost.guard.to_review' => array('guardReview'),
);
}
} |
由于有 EventDispatcher
and the AuditTrailListener
的帮助,你可以很容易地开启日志:
1 2 3 4 5 | use Symfony\Component\Workflow\EventListener\AuditTrailListener;
$logger = new AnyPsr3Logger();
$subscriber = new AuditTrailListener($logger);
$dispatcher->addSubscriber($subscriber); |
在Twig模板中使用工作流可以减少视图层中的域逻辑(domain logic)。考虑以下“博客控制台”的例程。下面的链接只在action被允许时才会显示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | <h3>Actions</h3>
{% if workflow_can(post, 'publish') %}
<a href="...">Publish article</a>
{% endif %}
{% if workflow_can(post, 'to_review') %}
<a href="...">Submit to review</a>
{% endif %}
{% if workflow_can(post, 'reject') %}
<a href="...">Reject article</a>
{% endif %}
{# Or loop through the enabled transistions #}
{# 或者遍历已开启的过渡 #}
{% for transition in workflow_transitions(post) %}
<a href="...">{{ transition.name }}</a>
{% else %}
No actions available.
{% endfor %} |
本文,包括例程代码在内,采用的是 Creative Commons BY-SA 3.0 创作共用授权。