zikula/wizard

该包已被废弃,不再维护。没有建议的替代包。

包含 Symfony 表单的多阶段交互向导

3.1.1 2020-12-12 14:55 UTC

This package is auto-updated.

Last update: 2022-09-18 09:55:32 UTC


README

向导已包含在核心仓库中。

向导

向导组件是多阶段用户交互的管理工具。它利用多个接口和向导类来创建一个与 Symfony 表单和 Twig 模板兼容的工作流程。依靠 阶段 的概念,开发者可以使用 .yml 文件定义一个序列,并在其控制器中控制该序列。

实例化时,向导类需要一个 StageContainer 和到 阶段定义文件(yaml 格式)的完整路径。向导将从那里加载阶段定义。向导组件为此包含一个 YamlFileLoader。

创建一个扩展 Zikula\Component\Wizard\AbstractStageContainer 的具体类。使用自动装配和自动配置来配置该类

_instanceof: # only works for classes that are configured in this file
    Zikula\Component\Wizard\StageInterface:
        tags: ['my_special_tag']

# if this is the only instance of the interface you will use, you can use an alias
Zikula\Component\Wizard\StageContainerInterface: '@Acme\Bundle\MyCustomBundle\Container\FooStageContainer'

Acme\Bundle\MyCustomBundle\Container\FooStageContainer:
    arguments:
        $stages: !tagged_iterator my_special_tag

阶段

阶段只是一个实现 StageInterface 的类。它定义了一个 名称、一个 模板名称 以及阶段将需要的任何 模板参数。阶段还必须定义它是否是 必需的,通过可能的逻辑完成并返回布尔值。标记为 NOT 必需的 的阶段将在其实例化和处理 isNecessary() 方法后跳过,允许该阶段在继续之前根据需要完成任务。当向导调用 getCurrentStage() 方法时,将跳过阶段。

使用 Symfony 自动装配和自动配置或手动依赖注入将服务添加到您的阶段。

阶段可以选择实现

  • InjectContainerInterface 如果阶段需要 Symfony 容器
  • FormHandlerInterface 如果阶段将使用 Symfony 表单

向导可以在 isNecessary() 方法中通过抛出 AbortStageException 来停止。该消息可以通过 $wizard->getWarning() 获取。

阶段定义文件

阶段定义文件是一个简单的 yaml 文件。第一个键 stages: 是必需的,然后每个阶段都应该通过 name 列出,每个都应该具有 classorder 属性。name 键必须与 Stage 类中设置的阶段名称相同。class 属性应该是完全限定的类名(带有命名空间),而 order 属性应该是一个标识阶段顺序的整数。可选地,一个阶段可以用一个 default 属性来识别,应该设置为 true。如果未提供阶段参数,该阶段将由向导使用。

sample_stages.yml 示例

stages:
    prep:
        class: Acme\Bundle\DemoBundle\Stage\PrepStage
        order: 1
        default: true
    getinfo:
        class: Acme\Bundle\DemoBundle\Stage\GetInfoStage
        order: 2
    noform:
        class: Acme\Bundle\DemoBundle\Stage\NoFormStage
        order: 3
    complete:
        class: Acme\Bundle\DemoBundle\Stage\CompleteStage
        order: 4
    nonstage:
        class: Acme\Bundle\DemoBundle\Stage\NonStage
        order: 99

示例控制器

use Symfony\Component\Form\FormFactoryInterface;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\RouterInterface;
use Zikula\Component\Wizard\FormHandlerInterface;
use Zikula\Component\Wizard\StageContainerInterface;
use Zikula\Component\Wizard\Wizard;
use Zikula\Component\Wizard\WizardCompleteInterface;

class MyController
{
    /**
     * @var StageContainerInterface
     */
    private $stageContainer;

    /**
     * @var \Twig\Environment
     */
    private $twig;

    /**
     * @var FormFactoryInterface
     */
    private $formFactory;

    /**
     * @var RouterInterface
     */
    private $router;

    /**
     * define route = 'index/{stage}'
     */
    public function indexAction(Request $request, $stage)
    {
        // begin the wizard
        $wizard = new Wizard($this->stageContainer, realpath(__DIR__ . '/../Resources/config/stages.yml'));
        $currentStage = $wizard->getCurrentStage($stage);
        if ($currentStage instanceof WizardCompleteInterface) {
            return $currentStage->getResponse($request);
        }
        $templateParams = $currentStage->getTemplateParams();
        if ($wizard->isHalted()) {
            $request->getSession()->getFlashBag()->add('danger', $wizard->getWarning());
            return new Response($this->twig->render('@MyCustomBundle/error.html.twig', $templateParams));
        }

        // handle the form
        if ($currentStage instanceof FormHandlerInterface) {
            $form = $this->formFactory->create($currentStage->getFormType());
            $form->handleRequest($request);
            if ($form->isSubmitted() && $form->isValid()) {
                $currentStage->handleFormResult($form);
                $url = $this->router->generate('index', ['stage' => $wizard->getNextStage()->getName()], true);

                return new RedirectResponse($url);
            }
            $templateParams['form'] = $form->createView();
        }

        return new Response($this->twig->render($currentStage->getTemplateName(), $templateParams));
    }
}

Flowchart