pablodip/module-bundle

Symfony PablodipModuleBundle

安装: 902

依赖: 1

建议者: 0

安全: 0

星级: 15

关注者: 1

分支: 3

开放问题: 0

类型:symfony-bundle

dev-master 2013-11-15 09:49 UTC

This package is not auto-updated.

Last update: 2024-09-14 11:44:46 UTC


README

Build Status Scrutinizer Quality Score

  1. 简介
  2. 创建模块
  3. 使模块可重用
  4. 扩展
  5. 重用模块

简介

Symfony2应用的目标是将HTTP请求转换为HTTP响应。这是通过控制器通过路由来实现的,因此可以说控制器是Symfony2应用中最重要的一部分,因为所有其他事情都由它们管理。

Symfony2为您提供了与控制器和路由一起工作的灵活性。一个控制器可以是任何PHP可调用对象,一个路由可以用多种格式定义,如YAML、XML、PHP、注解。这种灵活性很好,但有时您的应用程序会变得混乱,并且很难在应用程序之间重用东西。

PablodipModuleBundle允许您以模块的形式组织您的控制器和路由,使它们变得有序和可重用。有序的控制器是遵循某些顺序规则并将相关事物放在一起的控制。可重用模块是可以轻松定制并在同一项目或另一个项目中再次使用的模块。

组织控制器的常见规则是将它们放入束内的Controller目录。它们的名称有时与模型名称相同,并且您通常有一些用于静态动作的控制。

您应该如何组织一个博客,是将所有控制器放入同一个控制器类,还是将它们分割到不同的类中?如果您有一个仅用于博客的束,那么分割控制器是有意义的。但然后,您如何使该束可重用?您如何允许定制其行为?通过在容器中放置参数?通过在数据库中创建字段?不是更好吗?允许用户通过容器、数据库或任何他们想要的方式自定义它们?此外,您如何创建可重用的博客主题?Symfony2提供的模板覆盖功能很棒,但它不允许您创建主题。此外,您如何允许在同一个项目中多次使用博客?由于它只使用一组路由,并且它们在控制器和模板中是硬编码的,这将很难实现。

我们将了解如何使用PablodipModuleBundle来解决所有这些问题。

创建模块

为了将HTTP请求转换为HTTP响应,您需要一个控制器(也称为动作)和一个访问该控制器的路由。一个模块是一组相关动作。动作和模块都由类表示。

<?php

namespace Pablodip\BlogModuleBundle\Module;

use Pablodip\ModuleBundle\Module\Module;
use Pablodip\ModuleBundle\Action\RouteAction;
use Symfony\Component\HttpFoundation\Response;

class BlogModule extends Module
{
    protected function defineConfiguration()
    {
        $this->addActions(array(
            new RouteAction('blog_list', '/blog', 'GET', function () {
                // ...
                return new Response($content);
            }),
            new RouteAction('blog_post', '/blog/{id}', 'GET', function ($id) {
                // ...
                return new Response($content);
            }),
            // ...
        ));
    }
}

我们可以在代码中看到一些东西

  • 一个模块扩展自Pablodip\ModuleBundle\Module\Module类。
  • 模块配置在其defineConfiguration受保护方法中定义。
  • 模块可以有动作,您可以通过其addActions方法将动作添加到模块中。
  • 具有路由的动作扩展自Pablodip\ModuleBundle\Action\RouteAction类。
  • 具有路由的动作接受四个参数:路由名称、模式、方法和控制器。方法可以是方法或ANY表示任何方法。控制器可以是任何PHP可调用对象。
  • 控制器接收路由参数作为参数,就像在正常的Symfony2控制器中一样。
  • 控制器的作用是返回一个Response Symfony2类,就像在Symfony2中一样。
  • 放置模块的约定是将它们放入束的Module目录。
  • 模块命名的约定是使用Module后缀。

所有配置方法都实现了流畅的接口,因此您可以对它们进行链式调用。

操作名称

一个操作必须有一个名称。操作名称在模块中必须是唯一的。默认情况下,路由操作使用路由名称作为操作名称(因为路由名称在模块中也必须是唯一的),但您也可以自定义它

$action->setName('my_preferred_name');

路由前缀

在定义路由时,前面的例子有一个问题:所有操作中的路由名称和模式前缀都很相似。因此,您只需在一个地方定义它们,这样您就可以更容易地自定义它们。

protected function defineConfiguration()
{
    $this
        ->setRouteNamePrefix('blog_')
        ->setRoutePatternPrefix('/blog')
    ;

    $this->addActions(array(
        new RouteAction('list', '/', 'GET', function () {
            // ...
            return new Response($content);
        }),
        new RouteAction('post', '/{id}', 'GET', function ($id) {
            // ...
            return new Response($content);
        }),
        // ...
    ));
}

注意这样定义的操作路由更加简洁。最终定义的路由与之前相同,因为模块将模块路由前缀与操作路由名称连接起来。

您还可以使用快捷方式来定义路由前缀。

$this->setRoutePrefixes('blog_', '/blog');

生成模块URL

由于您可以在一个地方定义模块的路由名称前缀,因此您应该能够生成模块的URL,而无需每次都编写前缀。否则,如果您决定更改路由名称前缀,您将不得不更改所有硬编码的前缀。

为了做到这一点,您必须使用来自模块的 generateModuleUrl 方法

$url = $module->generateModuleUrl($actionName, $parameters, $absolute);

// normal
$listUrl = $module->generateModuleUrl('list'); // route generated: blog_list
// with parameters
$postUrl = $module->generateModuleUrl('post', array('id' => $id));
// absolute
$module->generateModuleUrl('list', array(), true);

容器访问

您可以在模块的任何时刻访问容器,因此您可以使用它来完成任何您想要的事情,包括配置。我们稍后会看到一些示例。

$container = $module->getContainer();

操作可以访问模块,因此它们也可以访问容器。

$module = $action->getModule();

// container
$container = $action->getModule()->getContainer();
$container = $action->getContainer(); // shortcut

// services
$validator = $action->getContainer()->get('validator);
$validator = $action->get('validator'); // shortcut

控制器

控制器接收路由的参数作为参数。它们还可以接收请求(如正常的Symfony2控制器)和操作。

new RouteAction('post', '/{id}', 'GET', function ($id, Request $request, RouteAction $action) {
})

接收操作很有用,因为您可以通过它访问容器。

操作实现了与Symfony2默认控制器相同的快捷方式

// shorcuts
$url = $action->generateUrl($routeName, $routeParameters);
$response = $action->redirect($url);
$response = $action->render($templateName, $templateParameters);
// ...
// (view full list in the Symfony2 default controller)

render 方法略有改进。您通常使用的模板具有以下格式:%bundle_name%:%module_name%:%action_name%.html.twig,因此它们很容易猜测。render 方法将通过传递参数数组作为第一个参数来尝试猜测模板名称。

namespace Pablodip\BlogModuleBundle\Module;

class BlogModule extends Module
{
    protected function defineConfiguration()
    {
        $this->addAction(new RouteAction('list', '/', 'GET', function (RouteAction $action) {
            // using full template
            return $action->render('PablodipModuleBundle:Blog:list.html.twig', array());

            // guessing template
            return $action->render(array()); // template guessed: PablodipModuleBundle:Blog:list.html.twig
        }));
    }
}

您应该只为自己的模块使用此猜测系统,而不是为可重用模块使用。

您还可以从操作中生成模块URL

$url = $action->generateModuleUrl($actionName, $parameters, $absolute);

模块视图

有时您需要从视图中访问模块,例如生成模块URL。您不应该直接将模块传递给视图,因为您可能不需要在视图中访问某些内容(例如容器)。相反,您应该使用 createView 方法生成一个用于视图的简化模块对象。

$moduleView = $module->createView();

// rendering a template
$container->get('templating')->render($templateName, array('module' => $module->createView()));

您可以按任何您想要的方式调用模块参数,但 module 是一个很好的约定。

然后您可以在视图中使用模块来生成URL

{# relative #}
{{ module.path('list') }}
{{ module.path('post', {'id': post.id}) }}

{# absolute #}
{{ module.url('list') }}

当您从操作中调用 render 方法时,模块会自动传递给视图。

我们稍后会看到模块视图的其他一些方法。

模块管理器

模块管理器创建并返回模块。当您需要访问其他模块时很有用。

$moduleManager = $container->get('module_manager');

$blogModule = $moduleManager->get('PablodipBlogModuleBundle:Blog');
// PablodipBlogModuleBundle/Module/BlogModule

$helpModule = $moduleManager->get('PablodipHelpModuleBundle:Help');
// PablodipHelpModuleBundle/Module/HelpModule

如您所见,您可以使用友好的语法来访问模块,只需写入包名和名称即可。

然后您可以生成URL或执行任何您想要的操作

$url = $blogModule->generateModuleUrl('list');

当您想在视图中使用模块时,可以通过 get_module twig 函数访问它,该函数直接返回视图模块对象

{{ get_module('PablodipBlogModuleBundle:Blog').path('list') }}

导入模块路由

为了使用模块中定义的路由,您必须将它们导入到路由文件配置中

pablodip_blog_module:
    resource: "@PablodipBlogModuleBundle/Module/BlogModule.php"
    type:     module

您还可以导入一个目录,这样其中的所有模块都将被导入

pablodip_blog_bundle_modules:
    resource: "@PablodipBlogBundle/Module"
    type:     module

在两种情况下,您都可以像在常规路由中一样使用前缀。

pablodip_blog_bundle_modules:
    resource: "@PablodipBlogBundle/Module"
    type:     module
    prefix:   /pablodip-blog-module

转发

您可以使用模块中的 forward 方法进行转发。

$response = $module->forward($actionName, $attributes);

$response = $module->forward('post', array('id' => $id));

有关转发的更多信息,请参阅 Symfony2 文档 这里

无路由的操作

有时您需要处理控制器,而不直接通过路由访问它们。为了做到这一点,您必须使用 Action 类。

use Pablodip\ModuleBundle\Action\Action;

new Action($actionName, $controller);

new Action('recentPosts', function ($max) {
    // process

    return Response($content);
});

请注意,在这里您必须指定操作名称,因为没有路由名称。

这些操作对于嵌入控制器非常有用,我们现在将看到这一点。

嵌入控制器

有时您需要嵌入控制器,就像在 Symfony2 文档 这里 所看到的那样。

您可以使用模块中的 render 方法来做到这一点。

{{ module.render(actionName, attributes) }}

{{ module.render(post, {'id': post.id}) }}

{{ get_module('PablodipBlogModuleBundle:Blog').render('post', {'id': post.id}) }}

独立操作

有时模块变得很大,因此由于操作只是类,我们可以创建独立的操作。

<?php

namespace Pablodip\BlogBundle\Action;

use Pablodip\ModuleBundle\Action\BaseRouteAction;
use Symfony\Component\HttpFoundation\Response;

class PostAction extends BaseRouteAction
{
    protected function defineConfiguration()
    {
        $this
            ->setRoute('show', '/{id}', 'GET')
            ->setController(function ($id) {
                // ...

                return new Response($content);
            })
        ;
    }
}

我们可以在代码中看到一些东西

  • 独立操作从 BaseRouteAction 类扩展,而不是从 RouteAction 类扩展。
  • 独立操作的配置在其 defineConfiguration 受保护的函数中定义。
  • 独立操作需要与常规路由操作相同的东西:路由名称、模式、方法和控制器。

控制器可以是任何 PHP 可调用函数,因此您可以进行如下操作

class ShowAction extends BaseAction
{
    protected function defineConfiguration()
    {
        $this
            ->setRoute('show', '/{id}', 'GET')
            ->setController(array($this, 'controller'))
        ;
    }

    public function controller($id)
    {
        // ...

        return new Response($content);
    }
}

这样,您在操作中使用的是正常方法,而不是闭包,因此您不需要将操作作为参数传递

public function controller($id)
{
    // action
    $this;

    // container
    $container = $this->getContainer();

    // render
    return $this->render(array());

    // you can use any action method this way
}

结论

我们已经看到了如何以有组织、灵活的方式创建模块和操作,以及如何导入它们的路由。我们看到了如何重用路由名称和模式前缀,以及如何访问容器。

您可以使用这种方法来创建控制器,这是很好的,因为您的代码将是组织良好的。但它甚至更好,因为您还可以轻松地使它们可重用和可自定义,我们现在将看到这一点。

使模块可重用

为了重用模块,您应该能够自定义它们。您应该能够自定义三个东西:选项、函数和路由。

  • 选项。任何参数,用于逻辑决策的布尔值,用于值的字符串,用于多个选项的数组等。
  • 函数。在模块内部使用。
  • 路由。模块和操作的路线名称和模式。

配置方法

当您定义配置时,您必须在 defineConfiguration 方法中完成,但当一个用户配置模块时,它必须在 configure 方法中完成。因此,defineConfiguration 方法必须用于您的模块以及创建可重用模块,而 configure 方法用于配置第三方模块。

class MyBlogModule extends BlogModule
{
    protected function configure()
    {
    }
}

操作访问

您可以通过名称访问操作

class MyBlogModule extends BlogModule
{
    protected function configure()
    {
        $listAction = $this->getAction('list');
        $postAction = $this->getAction('post');
    }
}

选项

选项可以是任何参数。您可以使用它们来定制逻辑决策,以及用于变量值或其他任何东西。

您可以通过 addOptionaddOptions 方法将选项添加到模块和操作中。选项需要一个名称和默认值。

在模块中定义选项

class BlogModule extends Module
{
    protected function defineConfiguration()
    {
        // ...

        $this->addOptions(arrray(
            'show_date'  => true,
            'email_from' => 'noreply@blogmodule.dev',
        ));
    }
}

在操作中定义选项

class ListAction extends BaseAction
{
    protected function defineConfiguration()
    {
        // ...

        $this->addOption('max_per_page', 10);
    }
}

然后您可以在您的控制器中使用这些选项

// module options
$optionValue = $action->getModule()->getOption($optionName);
$optionValue = $action->getModuleOption($optionName) // shortcut

if ($this->getModuleOption('show_date')) {
    // ...
}

$email->setFrom($action->getModuleOption('email_from'));

// action options
$pagerfanta->setMaxPerPage($action->getOption('max_per_page'));

同样,在您的模板中

{% if module.option('show_data') %}
    ...
{% endif %}

{{ module.actionOption('list', 'max_per_page') }}

用户可以通过 setOptionsetOptions 方法在模块中配置选项。

class MyBlogModule extends BlogModule
{
    protected function configure()
    {
        $this->setOptions(array(
            'show_date'  => false,
            'email_from' => 'my@email.com',
        ));
        $this->getAction('list')->setOption('max_per_page', 20);
        $this->setActionOption('list', 'max_per_page', 20); // shortcut
    }
}

使用选项自定义模板

您可以通过将模板放入选项中,允许用户自定义操作的模板。

class ListAction extends BaseAction
{
    protected function defineConfiguration()
    {
        $this
            ->setRoute('list', '/', 'GET')
            ->setController(array($this, 'controller'))
            ->addOption('template', 'PablodipBlogModuleBundle:Blog:list.html.twig')
        ;
    }

    public function controller()
    {
         // ...

        return $this->render($this->getTemplate());
    }
}

这样,用户只需更改 template 选项,就可以在操作中使用不同的模板

class MyBlogModule extends BlogModule
{
    protected function configure()
    {
        $this->setActionOption('list', 'template', 'MyBlogModuleBundle:Blog:list.html.twig');
    }
}

函数

当模块执行一些常见任务时,它通常会调用函数。这些函数可以是来自第三方库的函数或自己的函数,但它们是从模块中调用的。那么,为什么不让用户在需要时能够自定义这些函数呢?

让我们来看一个例子。您创建一个序列化事物的模块。您可以为序列化数据创建自己的函数,可以使用Symfony2序列化组件、JMSSerializerBundle,或者使用任何其他方式来序列化。您最终会使用类似下面的接口:

$serialized = serializeFunction($data, $format);
$unserialized = unserializeFunction($data, $type, $format);

那么为什么不使您的模块能够使用该接口的任何实现呢?

您只需要在模块中使用函数就可以做到这一点。

class BlogModule extends Module
{
    // ...

    public function serialize($data, $format)
    {
        // implement your serialization or use an external serialization library
    }

    public function deserialize($data, $type, $format)
    {
        // implementation
    }
}

您可以从控制器中调用这些函数。

$serialized = $module->serialize($data, $format);
$unserialized = $module->deserialize($data, $type, $format);

用户只需通过重写函数就可以更改实现。

class MyBlogModule extends BlogModule
{
    public function serialize($data, $format)
    {
        // my implementation
    }
}

解析配置

模块有一个名为 parseConfiguration 的受保护方法,在定义它们的配置并配置它们之后会被调用。此方法应用于检查配置是否正确,以及在需要时解析它。

class BlogModule extends Module
{
     // ...

    protected function parseConfiguration()
    {
        // checking configuration
        if (!$this->getOption('email_from')) {
            throw new \RuntimeException('The module requies the option "email_from".');
        }
    }
}

路由

用户可以自定义路由名称和模式前缀。

class MyBlogBundle extends BlogBundle
{
    protected function configure()
    {
        $this->setRoutePrefixes('my_blog_', '/my/blog');
    }
}

用户还可以自定义动作路由名称和模式。

$action->setRouteName('my_list')
$action->setRoutePattern('/my-list);

结论

我们已经看到了如何在模块中使用选项和函数。我们也看到了如何使用模块的路由系统,以允许用户尽可能多地自定义路由。所以总的来说,我们的模块已经变得完全可重用。

扩展

扩展允许您修改模块,从而可以通过它们获得更多的重用性。

扩展只是一个从 BaseExtension 类扩展的类。扩展必须实现 getName 方法,并可以实现对模块相同的三个配置方法。

<?php

namespace Pablodip\BlogModuleBundle\Extension;

use Pablodip\ModuleBundle\Extension\BaseExtension;

class FeedExtension extends BaseExtension
{
    public function getName()
    {
        return 'feed';
    }

    public function defineConfiguration()
    {
    }

    public function configure()
    {
    }

    public function parseConfiguration()
    {
    }
}

配置方法在模块中相同的这些方法之前被调用。您只需实现您使用的那些方法,就像在模块中一样。

注意扩展中的配置方法是公开的。

扩展可以通过 getModule 方法访问它所使用的模块。这样,扩展就可以修改模块的任何内容。但由于扩展配置方法在模块之前被调用,模块总是可以修改扩展。

class FeedExtension extends BaseExtension
{
    public function defineConfiguration()
    {
        $this->getModule()->addAction(new FeedAction());
    }
}

将使用此扩展的模块将有一个新的动作。

为了在您的模块中使用扩展,您必须通过使用 registerExtensions 受保护方法来注册它们。

class MyBlogModule extends BlogModule
{
    protected function registerExtensions()
    {
        $extensions = parent::registerExtensions();
        $extensions[] = new FeedExtension();

        return $extensions;
    }
}

您可以看到代码如何从父类调用该方法,然后添加更多的扩展。这是为了继续注册父类正在注册的扩展。

您可以在模块中通过名称访问扩展。

$feedExtension = $module->getExtension('feed');

您可以从扩展中按照您想要的任何方式修改模块,这样就可以获得很好的结果。让我们看看一些例子。

主题

主题只是一组针对某些动作的不同模板。您可以通过将模板作为选项放入,来自定义动作中使用的模板。这样,您可以通过自定义这些模板来创建主题,这可以通过扩展以良好的方式完成。

class CoolBlogTheme extends BaseExtension
{
    protected function configure()
    {
        $this->getModule()->getAction('list')->setOption('template', 'CoolBlogModuleThemeBundle:Blog:list.html.twig');
        $this->getModule()->getAction('post')->setOption('template', 'CoolBlogModuleThemeBundle:Blog:post.html.twig');
    }
}

您可以通过注册扩展在模块中使用此主题。

class MyBlogModule extends BlogModule
{
    protected function registerExtensions()
    {
        $extensions = parent::registerExtensions();
        $extensions[] = new CoolBlogTheme();

        return $extensions;
    }
}

重用常见任务

我们讨论了如何通过将它们放入函数中来在模块中重用常见任务。当我们需要序列化数据时,我们看到了一个例子。但如果我们需要在多个模块中使用序列化,我们是否需要为每个模块实现这些函数?如果我们实现这些函数,为什么不在不同的模块中重用这些实现呢?

我们可以通过将这些函数放入扩展来做这件事。

class SerializerExtension extends BaseExtension
{
    public function getName()
    {
        return 'serializer';
    }

    public function serialize($data, $format)
    {
        // implementation
    }

    public function unserialize($data, $type, $format)
    {
        // implementation
    }
}

这样,您只需通过注册扩展并使用它,就可以在多个模块中使用这些函数。

$serialized = $module->getExtension('serializer')->serialize($data, $format);

同一任务的扩展

您使用的一些扩展用于同一任务,因此允许为该任务创建更多实现,并适当地使用这些扩展将是个好主意。

让我们允许为序列化扩展创建更多实现,例如使用Symfony2序列化组件和JMSSerializerBundle。为了做到这一点,您需要一个基序列化扩展

abstract class BaseSerializerExtension extends BaseExtension
{
    public function getName()
    {
        return 'serializer';
    }

    abstract public function serialize($data, $format);

    abstract public function unserialize($data, $type, $format);
}

以及实现

class Symfony2SerializerExtension extends BaseSerializerExtension
{
    public function serialize($data, $format)
    {
        // implementation
    }

    public function unserialize($data, $type, $format)
    {
        // implementation
    }
}

class JMSSerializerBundleSerializerExtension extends BaseSerializerExtension
{
    public function serialize($data, $format)
    {
        // implementation
    }

    public function unserialize($data, $type, $format)
    {
        // implementation
    }
}

请注意,我们没有覆盖扩展名称,因为我们需要通过名称从模块中访问扩展。

您也可以对主题做同样的事情

abstract class BaseBlogThemeExtension extends BaseExtension
{
    protected function configure()
    {
        $this->getModule()->setActionOption('list', 'template', $this->getListTemplate());
        $this->getModule()->setActionOption('post', 'template', $this->getPostTemplate());
    }

    abstract protected function getListTemplate();

    abstract protected function getPostTemplate();
}

class CoolBlogThemeExtension extends BaseBlogThemeExtension
{
    protected function getListTemplate()
    {
        return 'CoolBlogModuleThemeBundle:Blog:list.html.twig';
    }

    protected function getPostTemplate()
    {
        return 'CoolBlogModuleThemeBundle:Blog:post.html.twig';
    }
}

现在,您有一个使用序列化扩展的模块,默认为Symfony2SerializerExtension,但您希望允许用户选择他偏好的实现。如果我们直接注册扩展,用户将不得不筛选已注册的扩展并注册他偏好的序列化扩展,这不是一个好方法。更好的方法是,在模块中创建一个用于注册序列化扩展的功能,并注册该扩展。

默认使用Symfony2Serializer扩展的模块

class BlogModule extends Module
{
    // ...

    protected function registerExtensions()
    {
        $extensions = parent::registerExtensions();
        $extensions[] = $this->registerSerializerExtension();

        return $extensions;
    }

    protected function registerSerializerExtension()
    {
        return new Symfony2SerializerExtension();
    }
}

这样用户可以轻松地更改序列化扩展

class MyBlogModule extends BlogModule
{
    protected function registerSerializerExtension()
    {
        return new JMSSerializerBundleSerializerExtension();
    }
}

如果您不想提供默认扩展,您可以同时将模块和注册扩展方法抽象化

abstract class BlogModule extends Module
{
    // ...

    protected function registerExtensions()
    {
        $extensions = parent::registerExtensions();
        $extensions[] = $this->registerSerializerExtension();

        return $extensions;
    }

    abstract protected function registerSerializerExtension();
}

Molino

Molino是一个制作工具持久化后端无关的库。这对于制作可重用模块来说很棒,因为如果您使用Molino API,您的模块将可以与任何molino一起工作:Mandango、Doctrine ORM、Doctrine ODM MongoDB等等。

为了做到这一点,您需要允许用户注册molino

abstract class BlogModule extends Module
{
    private $molino;

    public function getMolino()
    {
        return $this->molino;
    }

    protected function defineConfiguration()
    {
        $this->molino = $this->registerMolino();

        // ...
    }

    abstract protected function registerMolino();
}

这样用户可以选择他想要的molino

use Molino\Mandango\Molino;

class MyBlogModule extends BlogModule
{
    protected function registerMolino()
    {
        return new Molino($this->getContainer()->get('mandango'));
    }
}

您可以从控制器中使用molino

$molino = $module->getMolino();

但是,由于在可重用模块中与Molino一起工作是一个常见任务,让我们看看官方为此提供的扩展。基础抽象类是Pablodip\ModuleBundle\Extension\Molino\BaseMolinoExtension,它有一个抽象受保护的registerMolino方法,以及一个getMolino方法来访问molino。每个molino实现都有一个molino扩展。

Pablodip\ModuleBundle\Extension\Molino\MandangoMolinoExtension
Pablodip\ModuleBundle\Extension\Molino\DoctrineORMMolinoExtension

这些扩展使用容器来注册molino。

您可以使用它们与事件一起使用

$extension = new MandangoMolinoExtension(true);
$eventDispatcher = $extension->getEventDispatcher();

您可以从扩展中获取molino,也可以使用操作的快捷方式

$molino = $action->getModule()->getExtension('molino')->getMolino();

// shortcut
$molino = $action->getMolino();

当与Molino一起工作时,您必须使用模型类,因此将其作为一个选项是个好主意。

abstract class BlogModule extends MolinoModule
{
    protected function defineConfiguration()
    {
        $this->addOption('postClass', null);

        // ...
    }

    protected function parseConfiguration()
    {
        if (null === $this->getOption('postClass')) {
            throw new \RuntimeException('The option "postClass" is required in a BlogModule.');
        }
    }
}

这样,您可以在控制器中像这样使用Molino

class PostAction extends BaseAction
{
    // ...

    public function controller($id)
    {
        $post = $molino->findOneById($this->getModuleOption('postClass'), $id);

        // ...
    }
}

重用模块

模块只是类,因此扩展模块就像扩展类一样简单。您可以在项目中拥有尽可能多的模块,真正使用的只是您导入路由的模块。因此,您可以在同一项目中多次使用相同的模块,以您想要的方式对每个模块进行定制。

让我们创建一些博客。

一个使用Mandango和Cool主题的博客。

class MyMandangoBlogModule extends BlogModule
{
    protected function registerExtensions()
    {
        $extensions = parent::registerExtensions();
        $extensions[] = new CoolBlogModuleThemeExtension();

        return $extensions;
    }

    protected configure()
    {
        $this
            ->setRoutePrefixes('my-mandango-blog_', '/my/mandango/blog')
            ->setOption('postClass', 'Model\Mandango\Post')
        ;
    }

    protected function registerMolinoExtension()
    {
        return new MandangoMolinoExtension();
    }
}

一个带有feed的Doctine ORM博客。

class MyDoctrineORMBlogModule extends BlogModule
{
    protected function registerExtensions()
    {
        $extensions = parent::registerExtensions();
        $extensions[] = new FeedExtension();

        return $extensions;
    }

    protected configure()
    {
        $this
            ->setRoutePrefixes('my-doctrine-orm-blog_', '/my/doctrine-orm/blog')
            ->setOption('postClass', 'Model\Doctrine\ORM\Post')
        ;
    }

    protected function registerMolino()
    {
        return new DoctrineORMMolinoExtension();
    }
}

结论

您可以按您想要的方式和次数自定义模块。您可以在系统之上创建许多东西,它们可以因为Molino的持久化后端无关性而工作,它们可以拥有主题,它们可以按您想要的程度进行自定义。

重用东西对每个人都是有益的。您可以与他人分享东西,也可以使用他人的东西。

作者

帕布洛·迪埃兹 - pablodip@gmail.com

许可证

PablodipModuleBundle根据MIT许可证授权。有关详细信息,请参阅LICENSE文件。