webrider / cake-dm
CakePHP 3 的域管理器
Requires
- php: >=5.6.0
- cakephp/cakephp: ~3.8
- haydenpierce/class-finder: ^0.4.0
Requires (Dev)
- phpunit/phpunit: ^5.7.14|^6.0
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/Internal 和 src/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