webrider/cake-dm

CakePHP 3 的域管理器

1.3.1 2019-12-16 02:58 UTC

This package is auto-updated.

Last update: 2024-09-16 13:51:48 UTC


README

一个 CakePHP 应用程序的层管理器。

简介

随着 CakePHP 的增长,相应的控制器、模型和模板文件夹的尺寸也会增加。

如果你的 src/Template/Element 文件夹没有分成几个子文件夹,它可能已经变得一团糟。

新加入的人会想知道从哪里开始,就像你一样,不知道哪些模型与另一个相关。

另一种选择是将所有内容拆分成插件。但这可能不是你对插件所期望的。你最终会在真正的插件中添加大量插件,并且 src 文件夹会被废弃。

子文件夹!这是 cake-dm 提出的方法。考虑到域分离,这个包建议将你的 MVC 结构拆分成层。以及子层。

要求

CakePHP >= 3.5

安装

使用 composer,运行

composer require webrider/cake-dm

示例

没有 cake-dm

假设以下是一个航班公司的最小化结构。

- src
    - Console
    - Controller
        - Component
            GeneralComponent.php
            UserRelatedComponent.php       
        AdminController.php
        AppController.php
        DiscountsController.php
        FlightsController.php
        InvoicesController.php
        MachinesController.php
        PagesController.php
        PilotsController.php
        SeatsController.php       
        StewardsController.php
        TicketsController.php
        UsersController.php
        UserProfilesController.php
    - Model
        - Table
            AppTable.php
            DiscountsTable.php
            FlightsTable.php
            ...
        - Entity
        ...
    - Template
        - Admin
        - Discounts
        - Flights
        - Element
            company_logo.ctp
            flight_description.ctp
            user_avatar.ctp            
        - Invoices
        - Layout
            default.ctp
        - Machines
        ...
    - View
        - Cell
        - Helper
        AjaxView.php
        AppView.php
    Application.php

使用 cake-dm

Cake-dm 使得能够以以下方式组织代码

- src     
    - Admin
        - Controller
            AdminController.php
        - Template
            - Layout
                default.ctp 
    - App
        - Console
        - Controller
            - Component
                GeneralComponent.php                   
            - AppController.php
            - PagesController.php
        - Model
        - Template
            - Element
                company_logo.ctp
            - Layout
                default.ctp                            
        - View
            - Cell
            - Helper
            AjaxView.php
            AppView.php               
        Application.php        
    - Invoicing
        - Controller              
            DiscountsController.php
            TicketsController.php
        - Model
        - Template                
    - Logistic
        - Controller
            FlightsController.php
            MachinesController.php
            SeatsController.php
        - Model
        - Template
            - Element
                - Flight
                    flight_description.ctp
            - Flights
            - Machines
            - Seats
    - Staff          
    - User
        - Controller
            - Component             
                UserRelatedComponent.php
            UsersController.php
            UserProfilesController.php
        - Model
            - Table
                UsersTable.php
                UserProfilesTable.php
            - Entity
        - Template
            - Element
                user_avatar.ctp
            - Users
            - UserProfiles

优点是

  • 你的应用结构变得更加清晰。
  • 应用的不同域可以清楚地分配给不同的开发者或团队。
  • 模板路径累积。例如,在这里,层 Admin 内的所有模板布局与其他模板不同。这可以从结构中轻松阅读。
  • 如果在一个层中找不到模板、布局或元素,它将默认在 App/Template 中搜索。
  • 元素和组件可以根据其相关性分布在层中。

请注意

  • 可以将层拆分为子层,例如通过创建 src/Staff/Internalsrc/Staff/External 文件夹。在这种情况下,不应在 src/Staff 文件夹中放置任何 MVC 文件夹。
  • 域层名称 App 实际上应该是你的应用程序命名空间,在 CakePHP 中默认为 App。对于插件,它应该是 Plugin,无论插件的名称如何。
  • 插件结构可以以相同的方式进行拆分。然后应该用 Plugin 域层替换 App 域层。
  • 命名空间不会改变。因此,禁止在层中有两个具有相同名称的类。下面将详细介绍。
  • 单元格、视图、行为和辅助器可以像组件一样分布在域层中。

设置

结构由三个组件管理。

Composer

为了使 Cake 按路径执行而不改变命名空间并干扰中间件,您必须在您的 composer.json 文件中修改以下内容

"autoload": {
    "psr-4": {
        "App\\": [           
            "src/Admin",
            "src/App",
            "src/Invoicing",
            "src/Logistic",
            "src/Staff",
            "src/User"
        ],
        ...
    }
},

在任何结构更改后,运行 composer dump-autoload

当在您的插件中引入域层时,这也适用。

控制器

在您的 AppController.php 中,应在 AppController::initialize() 中尽早添加到模板的相关路径。

Cake-dm 将知道请求是在哪个层中执行的。它将包含该层的模板路径以及 App 层。为此,请添加

...

use CakeDomainManager\DomainController;

...

class AppController extends Controller
{

    ...

    public function initialize()
    {
        ...
        
        DomainController::init($this)->setTemplatePaths();
    }

    ...

}

视图

在视图中,我们需要改变元素加载的方式。在你的 AppView.php 文件中,你应该重写 Cake\View\View 类的 _getElementFileName() 方法。

为了实现这一点,在 AppView.php

...

use CakeDomainManager\DomainView;

...

class AppView extends View
{
    ...

    /**
     * @param string $name
     * @param bool $pluginCheck
     * @return false|string
     */
    protected function _getElementFileName($name, $pluginCheck = true)
    {
        return DomainView::init($this)->_getElementFileName($name, $pluginCheck);
    }

    ...
}

可选 1

在一个相同的命名空间下有多个目录(参见 Composer),存在一个风险,即开发者在某个目录中创建一个类,在另一个目录中创建了一个同名类。这是在MVC中添加一个层的代价。

如果发生这种情况,PHP 和 Composer 不会抛出任何错误或警告。

为了避免这种情况,你可以在你的 ApplicationTest.php 文件中添加以下测试,以确保所有类都能通过 Composer 正确访问。

...

use Cake\Error\FatalErrorException;
use Cake\Log\Log;
use CakeDomainManager\DomainApplication;

...

    /**
     * Makes sure that the domain structure is coherent
     * @throws \ReflectionException
     */
    public function testTrackDuplicatedClassesInNamespaceNoError()
    {
        $error = false;
        try {
            $app = new Application(dirname(dirname(__DIR__)) . '/config');
            DomainApplication::init($app)->trackDuplicatedClassesInNamespace(
                Configure::read('App.namespace', 'App'),
                APP
            );
        } catch (FatalErrorException $exception) {
            Log::error($error = $exception->getMessage());
        }

        $this->assertEquals(false, $error, $error);
    }
...

如果你绝对需要在 src 文件夹中拥有两个同名类,当前版本的包无法做到这一点。

可选 2

我建议编辑你 config/app.php 文件中的 'App.paths' 条目下的以下行

'templates' => [APP . DS . 'App' . DS . 'Template' . DS],

或者如果你的应用命名空间不是 App,则使用你的应用命名空间。

如果在安装过程中遇到任何错误信息,Cake 将知道错误模板的路径。

迁移完成后,可以最终删除此条目。DomainController 会为你设置该路径,如上文中 Controller 部分所述。

用法

完成设置后,你可以像以前一样调用同一层的元素

Request: /users/view/1

<?= $this->element('user_avatar', compact('user')) ?>

要调用另一层的元素,只需在传统的 CakePHP 语法末尾使用魔法 @ 符号。

另一层的元素

Request: /pilots/view/1
<?= $this->element('user_avatar@User', ['user' => $pilot->user]) ?>

另一个子层的元素,例如 User/Settings

Request: /pilots/view/1
<?= $this->element('user_avatar@User/Settings', ['user' => $pilot->user]) ?>

另一个分层插件的元素

E.g.: plugins/Advertisements/src/CarRenting/Template/Element/weekly_offers.ctp

Request: /pilots/view/1
<?= $this->element('Advertisements.weekly_offers@CarRenting', compact('weekly_offers')) ?>

该表示法

<?= $this->element('../Users', compact('users)) ?>

不再受支持,或者至少可能产生不可预测的反应。相反,以所有可重用模板都位于域层 Element 文件夹的方式组织你的结构。并使用魔法 @ 符号调用域层之间的元素。

鸣谢

Juan Pablo Ramirez

webrider.de

许可

MIT