CakePHP 4 在插件中烘焙自定义模板命令
CakePHP 4 Bake Custom TemplateCommand in Plugin
我似乎无法从我的插件中覆盖 TemplateCommand
。
原始 TemplateCommand
位于:vendor/cakephp/bake/src/Command/TemplateCommand.php
namespace Bake\Command;
...
class TemplateCommand extends BakeCommand
{...}
我把我的存储在这里:plugins/MyPlugin/src/Command/TemplateCommand
:
namespace MyPlugin\Bake\Command;
...
use Bake\Command\TemplateCommand as MyTemplateCommand;
class TemplateCommand extends MyTemplateCommand
{...}
当我运行bin/cake bake template books -t "MyPlugin"
时,我得到:
Fatal error: Cannot declare class MyPlugin\Bake\Command\TemplateCommand, because the name is already in use in C:\path\to\app\plugins\MyPlugin\src\Command\TemplateCommand.php on line 39
编辑#2
在 Plugin.php
中,在 bootstrap()
中,我能够调试加载的插件。
[
(int) 0 => 'AuditStash',
(int) 1 => 'Bake',
(int) 2 => 'DebugKit',
(int) 3 => 'Migrations',
(int) 4 => 'MyPlugin'
]
编辑 #3
在plugins/MyPlugin/src/Command/TemplateCommand.php
中,我在输出中添加了***MYPLUGIN***
。
namespace MyPlugin\Command;
...
use Bake\Command\TemplateCommand as MyPluginTemplateCommand;
class TemplateCommand extends MyPluginTemplateCommand
{
...
public function bake(
Arguments $args,
ConsoleIo $io,
string $template,
$content = '',
?string $outputFile = null
): void {
if ($outputFile === null) {
$outputFile = $template;
}
if ($content === true) {
$content = $this->getContent($args, $io, $template);
}
if (empty($content)) {
$io->err("<warning>No generated content for '{$template}.php', not generating template.</warning>");
return;
}
$path = $this->getTemplatePath($args);
$filename = $path . Inflector::underscore($outputFile) . '.php';
$io->out("\n" . sprintf('***MYPLUGIN*** Baking `%s` view template file...', $outputFile), 1, ConsoleIo::QUIET);
$io->createFile($filename, $content, $args->getOption('force'));
}
...
}
当我 运行 bin/bake template books -t MyPlugin
时,我看到这条消息没有添加前缀:
Baking
索引 view template file...
它似乎没有接收到我的 class。
编辑#4
在vendor/cakephp/cakephp/src/Console/CommandRunner.php
函数run
中,我添加了var_dump
:
...
$shell = $this->getCommand($io, $commands, $name);
var_dump($commands);
...
输出:
object(Cake\Console\CommandCollection)#33 (1) {
["commands":protected]=>
array(87) {
["help"]=>
string(32) "Cake\Console\Command\HelpCommand"
["version"]=>
string(27) "Cake\Command\VersionCommand"
["cache clear"]=>
string(30) "Cake\Command\CacheClearCommand"
["cache clear_all"]=>
string(33) "Cake\Command\CacheClearallCommand"
["cache list"]=>
string(29) "Cake\Command\CacheListCommand"
["completion"]=>
string(30) "Cake\Command\CompletionCommand"
["i18n"]=>
string(24) "Cake\Command\I18nCommand"
["i18n extract"]=>
string(31) "Cake\Command\I18nExtractCommand"
["i18n init"]=>
string(28) "Cake\Command\I18nInitCommand"
["plugin assets copy"]=>
string(36) "Cake\Command\PluginAssetsCopyCommand"
["plugin assets remove"]=>
string(38) "Cake\Command\PluginAssetsRemoveCommand"
["plugin assets symlink"]=>
string(39) "Cake\Command\PluginAssetsSymlinkCommand"
["plugin load"]=>
string(30) "Cake\Command\PluginLoadCommand"
["plugin loaded"]=>
string(32) "Cake\Command\PluginLoadedCommand"
["plugin unload"]=>
string(32) "Cake\Command\PluginUnloadCommand"
["routes check"]=>
string(31) "Cake\Command\RoutesCheckCommand"
["routes"]=>
string(26) "Cake\Command\RoutesCommand"
["routes generate"]=>
string(34) "Cake\Command\RoutesGenerateCommand"
["schema_cache build"]=>
string(36) "Cake\Command\SchemacacheBuildCommand"
["schema_cache clear"]=>
string(36) "Cake\Command\SchemacacheClearCommand"
["server"]=>
string(26) "Cake\Command\ServerCommand"
["console"]=>
string(22) "App\Shell\ConsoleShell"
["model"]=>
string(29) "MyPlugin\Command\ModelCommand"
["my_plugin.model"]=>
string(29) "MyPlugin\Command\ModelCommand"
["template"]=>
string(32) "MyPlugin\Command\TemplateCommand"
["my_plugin.template"]=>
string(32) "MyPlugin\Command\TemplateCommand"
...
string(25) "Bake\Command\ModelCommand"
["bake template"]=>
string(28) "Bake\Command\TemplateCommand"
...
}
}
在vendor/cakephp/cakephp/src/Console/CommandScanner.php
中添加了var_dump
:
public function scanPlugin(string $plugin): array
{
if (!Plugin::isLoaded($plugin)) {
return [];
}
$path = Plugin::classPath($plugin);
$namespace = str_replace('/', '\', $plugin);
$prefix = Inflector::underscore($plugin) . '.';
$commands = $this->scanDir($path . 'Command', $namespace . '\Command\', $prefix, []);
$shells = $this->scanDir($path . 'Shell', $namespace . '\Shell\', $prefix, []);
var_dump($commands);
return array_merge($shells, $commands);
}
输出:
array(0) {
}
array(2) {
[0]=>
array(4) {
["file"]=>
string(94) "C:\path\to\MyPlugin\src\CommandModelCommand.php"
["fullName"]=>
string(15) "my_plugin.model"
["name"]=>
string(5) "model"
["class"]=>
string(29) "MyPlugin\Command\ModelCommand"
}
[1]=>
array(4) {
["file"]=>
string(97) "C:\path\to\MyPlugin\src\CommandTemplateCommand.php"
["fullName"]=>
string(18) "my_plugin.template"
["name"]=>
string(8) "template"
["class"]=>
string(32) "MyPlugin\Command\TemplateCommand"
}
}
...
编辑#5
我想我明白了!
namespace MyPlugin\Command;
use Bake\Command\TemplateCommand as MyPluginTemplateCommand;
class TemplateCommand extends MyPluginTemplateCommand
{...}
我还在bootstrap()
函数的最后一行添加了我的插件。
CLI 的输出现在反映了我所做的更改。
编辑 #6
需要弄清楚为什么它没有将视图写入适当的文件夹。它在书籍上翻了一番:src/templates/Books/Books
编辑 #7
为了摆脱路径中的重复,注释掉函数 getTemplatePath
。
编辑#8
最终解决方案。
使用的 class 定义,也更新了编辑 #5。
namespace MyPlugin\Command;
use Bake\Command\TemplateCommand as MyPluginTemplateCommand;
class TemplateCommand extends MyPluginTemplateCommand
{...}
您的命名空间错误,class 文件的路径中没有 Bake
文件夹。这种不匹配将导致检查 class' 是否存在失败,并随后导致自动加载器多次加载文件,从而导致您看到的错误,因为 class 只能被声明一次。
我似乎无法从我的插件中覆盖 TemplateCommand
。
原始 TemplateCommand
位于:vendor/cakephp/bake/src/Command/TemplateCommand.php
namespace Bake\Command;
...
class TemplateCommand extends BakeCommand
{...}
我把我的存储在这里:plugins/MyPlugin/src/Command/TemplateCommand
:
namespace MyPlugin\Bake\Command;
...
use Bake\Command\TemplateCommand as MyTemplateCommand;
class TemplateCommand extends MyTemplateCommand
{...}
当我运行bin/cake bake template books -t "MyPlugin"
时,我得到:
Fatal error: Cannot declare class MyPlugin\Bake\Command\TemplateCommand, because the name is already in use in C:\path\to\app\plugins\MyPlugin\src\Command\TemplateCommand.php on line 39
编辑#2
在 Plugin.php
中,在 bootstrap()
中,我能够调试加载的插件。
[
(int) 0 => 'AuditStash',
(int) 1 => 'Bake',
(int) 2 => 'DebugKit',
(int) 3 => 'Migrations',
(int) 4 => 'MyPlugin'
]
编辑 #3
在plugins/MyPlugin/src/Command/TemplateCommand.php
中,我在输出中添加了***MYPLUGIN***
。
namespace MyPlugin\Command;
...
use Bake\Command\TemplateCommand as MyPluginTemplateCommand;
class TemplateCommand extends MyPluginTemplateCommand
{
...
public function bake(
Arguments $args,
ConsoleIo $io,
string $template,
$content = '',
?string $outputFile = null
): void {
if ($outputFile === null) {
$outputFile = $template;
}
if ($content === true) {
$content = $this->getContent($args, $io, $template);
}
if (empty($content)) {
$io->err("<warning>No generated content for '{$template}.php', not generating template.</warning>");
return;
}
$path = $this->getTemplatePath($args);
$filename = $path . Inflector::underscore($outputFile) . '.php';
$io->out("\n" . sprintf('***MYPLUGIN*** Baking `%s` view template file...', $outputFile), 1, ConsoleIo::QUIET);
$io->createFile($filename, $content, $args->getOption('force'));
}
...
}
当我 运行 bin/bake template books -t MyPlugin
时,我看到这条消息没有添加前缀:
Baking
索引 view template file...
它似乎没有接收到我的 class。
编辑#4
在vendor/cakephp/cakephp/src/Console/CommandRunner.php
函数run
中,我添加了var_dump
:
...
$shell = $this->getCommand($io, $commands, $name);
var_dump($commands);
...
输出:
object(Cake\Console\CommandCollection)#33 (1) {
["commands":protected]=>
array(87) {
["help"]=>
string(32) "Cake\Console\Command\HelpCommand"
["version"]=>
string(27) "Cake\Command\VersionCommand"
["cache clear"]=>
string(30) "Cake\Command\CacheClearCommand"
["cache clear_all"]=>
string(33) "Cake\Command\CacheClearallCommand"
["cache list"]=>
string(29) "Cake\Command\CacheListCommand"
["completion"]=>
string(30) "Cake\Command\CompletionCommand"
["i18n"]=>
string(24) "Cake\Command\I18nCommand"
["i18n extract"]=>
string(31) "Cake\Command\I18nExtractCommand"
["i18n init"]=>
string(28) "Cake\Command\I18nInitCommand"
["plugin assets copy"]=>
string(36) "Cake\Command\PluginAssetsCopyCommand"
["plugin assets remove"]=>
string(38) "Cake\Command\PluginAssetsRemoveCommand"
["plugin assets symlink"]=>
string(39) "Cake\Command\PluginAssetsSymlinkCommand"
["plugin load"]=>
string(30) "Cake\Command\PluginLoadCommand"
["plugin loaded"]=>
string(32) "Cake\Command\PluginLoadedCommand"
["plugin unload"]=>
string(32) "Cake\Command\PluginUnloadCommand"
["routes check"]=>
string(31) "Cake\Command\RoutesCheckCommand"
["routes"]=>
string(26) "Cake\Command\RoutesCommand"
["routes generate"]=>
string(34) "Cake\Command\RoutesGenerateCommand"
["schema_cache build"]=>
string(36) "Cake\Command\SchemacacheBuildCommand"
["schema_cache clear"]=>
string(36) "Cake\Command\SchemacacheClearCommand"
["server"]=>
string(26) "Cake\Command\ServerCommand"
["console"]=>
string(22) "App\Shell\ConsoleShell"
["model"]=>
string(29) "MyPlugin\Command\ModelCommand"
["my_plugin.model"]=>
string(29) "MyPlugin\Command\ModelCommand"
["template"]=>
string(32) "MyPlugin\Command\TemplateCommand"
["my_plugin.template"]=>
string(32) "MyPlugin\Command\TemplateCommand"
...
string(25) "Bake\Command\ModelCommand"
["bake template"]=>
string(28) "Bake\Command\TemplateCommand"
...
}
}
在vendor/cakephp/cakephp/src/Console/CommandScanner.php
中添加了var_dump
:
public function scanPlugin(string $plugin): array
{
if (!Plugin::isLoaded($plugin)) {
return [];
}
$path = Plugin::classPath($plugin);
$namespace = str_replace('/', '\', $plugin);
$prefix = Inflector::underscore($plugin) . '.';
$commands = $this->scanDir($path . 'Command', $namespace . '\Command\', $prefix, []);
$shells = $this->scanDir($path . 'Shell', $namespace . '\Shell\', $prefix, []);
var_dump($commands);
return array_merge($shells, $commands);
}
输出:
array(0) {
}
array(2) {
[0]=>
array(4) {
["file"]=>
string(94) "C:\path\to\MyPlugin\src\CommandModelCommand.php"
["fullName"]=>
string(15) "my_plugin.model"
["name"]=>
string(5) "model"
["class"]=>
string(29) "MyPlugin\Command\ModelCommand"
}
[1]=>
array(4) {
["file"]=>
string(97) "C:\path\to\MyPlugin\src\CommandTemplateCommand.php"
["fullName"]=>
string(18) "my_plugin.template"
["name"]=>
string(8) "template"
["class"]=>
string(32) "MyPlugin\Command\TemplateCommand"
}
}
...
编辑#5
我想我明白了!
namespace MyPlugin\Command;
use Bake\Command\TemplateCommand as MyPluginTemplateCommand;
class TemplateCommand extends MyPluginTemplateCommand
{...}
我还在bootstrap()
函数的最后一行添加了我的插件。
CLI 的输出现在反映了我所做的更改。
编辑 #6
需要弄清楚为什么它没有将视图写入适当的文件夹。它在书籍上翻了一番:src/templates/Books/Books
编辑 #7
为了摆脱路径中的重复,注释掉函数 getTemplatePath
。
编辑#8
最终解决方案。
使用的 class 定义,也更新了编辑 #5。
namespace MyPlugin\Command;
use Bake\Command\TemplateCommand as MyPluginTemplateCommand;
class TemplateCommand extends MyPluginTemplateCommand
{...}
您的命名空间错误,class 文件的路径中没有 Bake
文件夹。这种不匹配将导致检查 class' 是否存在失败,并随后导致自动加载器多次加载文件,从而导致您看到的错误,因为 class 只能被声明一次。