PSR-4 – 永夜 https://www.shuijingwanwq.com 没有不值得去解决的问题,也没有不值得去学习的技术! Sat, 30 May 2026 09:38:42 +0000 zh-Hans hourly 1 https://wordpress.org/?v=7.0 在 Laravel 6 中的模块(nWidart/laravel-modules:7.3)上定义调度任务 https://www.shuijingwanwq.com/2023/01/07/7330/ https://www.shuijingwanwq.com/2023/01/07/7330/#respond Sat, 07 Jan 2023 02:27:59 +0000 https://www.shuijingwanwq.com/?p=7330 浏览量: 237 1、生成一个新模块:Blog。


PS E:\wwwroot\laravel6-modules-demo> php artisan module:make Blog
Created : E:\wwwroot\laravel6-modules-demo\Modules/Blog/module.json
Created : E:\wwwroot\laravel6-modules-demo\Modules/Blog/Routes/web.php
Created : E:\wwwroot\laravel6-modules-demo\Modules/Blog/Routes/api.php
Created : E:\wwwroot\laravel6-modules-demo\Modules/Blog/Resources/views/index.blade.php
Created : E:\wwwroot\laravel6-modules-demo\Modules/Blog/Resources/views/layouts/master.blade.php
Created : E:\wwwroot\laravel6-modules-demo\Modules/Blog/Config/config.php
Created : E:\wwwroot\laravel6-modules-demo\Modules/Blog/composer.json
Created : E:\wwwroot\laravel6-modules-demo\Modules/Blog/Resources/assets/js/app.js
Created : E:\wwwroot\laravel6-modules-demo\Modules/Blog/Resources/assets/sass/app.scss
Created : E:\wwwroot\laravel6-modules-demo\Modules/Blog/webpack.mix.js
Created : E:\wwwroot\laravel6-modules-demo\Modules/Blog/package.json
Created : E:/wwwroot/laravel6-modules-demo/Modules/Blog/Database/Seeders/BlogDatabaseSeeder.php
Created : E:/wwwroot/laravel6-modules-demo/Modules/Blog/Providers/BlogServiceProvider.php
Created : E:/wwwroot/laravel6-modules-demo/Modules/Blog/Providers/RouteServiceProvider.php
Created : E:/wwwroot/laravel6-modules-demo/Modules/Blog/Http/Controllers/BlogController.php
Module [Blog] created successfully.


2、默认情况下,模块类不会自动加载。 你可以使用 psr-4 自动加载你的模块。编辑 composer.json。如图1
默认情况下,模块类不会自动加载。 你可以使用 psr-4 自动加载你的模块。编辑 composer.json

图1



    "autoload": {
        "psr-4": {
            "App\\": "app/",
            "Modules\\": "Modules/"
        }
    },


3、提示:不要忘记之后运行 composer dump-autoload。如图2
提示:不要忘记之后运行 composer dump-autoload

图2



PS E:\wwwroot\laravel6-modules-demo> composer dump-autoload
Generating optimized autoload files
> Illuminate\Foundation\ComposerScripts::postAutoloadDump
> @php artisan package:discover --ansi
Discovered Package: facade/ignition
Discovered Package: fideloper/proxy
Discovered Package: laravel/tinker
Discovered Package: nesbot/carbon
Discovered Package: nunomaduro/collision
Discovered Package: nwidart/laravel-modules
Package manifest generated successfully.
Generated optimized autoload files containing 4360 classes


4、为指定模块生成给定的控制台命令。


PS E:\wwwroot\laravel6-modules-demo> php artisan module:make-command CreatePostCommand Blog
Created : E:/wwwroot/laravel6-modules-demo/Modules/Blog/Console/CreatePostCommand.php


5、编辑 CreatePostCommand.php,主要修改 $name 属性与 handle 方法
<pre class="wp-block-syntaxhighlighter-code">

<?php

namespace Modules\Blog\Console;

use Illuminate\Console\Command;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputArgument;

class CreatePostCommand extends Command
{
    /**
     * The console command name.
     *
     * @var string
     */
    protected $name = 'blog:create-post';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Command description.';

    /**
     * Create a new command instance.
     *
     * @return void
     */
    public function __construct()
    {
        parent::__construct();
    }

    /**
     * Execute the console command.
     *
     * @return mixed
     */
    public function handle()
    {
        file_put_contents(storage_path() . '/logs/Modules-Blog-Console-CreatePostCommand-handle-' . microtime(true) . '-' . mt_rand()  . '.txt', print_r([], true), FILE_APPEND | LOCK_EX);
    }

    /**
     * Get the console command arguments.
     *
     * @return array
     */
    protected function getArguments()
    {
        return [
            ['example', InputArgument::REQUIRED, 'An example argument.'],
        ];
    }

    /**
     * Get the console command options.
     *
     * @return array
     */
    protected function getOptions()
    {
        return [
            ['example', null, InputOption::VALUE_OPTIONAL, 'An example option.', null],
        ];
    }
}


</pre>
6、注册命令,使用服务提供者类中可用的名为 commands 的 laravel 方法注册该命令。


    /**
     * Register the service provider.
     *
     * @return void
     */
    public function register()
    {
        $this->app->register(RouteServiceProvider::class);
        $this->commands([
            \Modules\Blog\Console\CreatePostCommand::class,
        ]);
    }


7、要查看所有可用的 Artisan 命令的列表,可以使用 list 命令:确认 blog:create-post 已存在。如图3
要查看所有可用的 Artisan 命令的列表,可以使用 list 命令:确认 blog:create-post 已存在

图3

8、执行:php artisan blog:create-post 时报错:Not enough arguments (missing: “example”).


PS E:\wwwroot\laravel6-modules-demo> php artisan blog:create-post


  Not enough arguments (missing: "example").




9、编辑 CreatePostCommand.php ,删除掉方法 getArguments 10、再次执行:php artisan blog:create-post,不再报错。查看执行结果,有输出日志文件:Modules-Blog-Console-CreatePostCommand-handle-1672371310.181-805184791.txt 。如图4
再次执行:php artisan blog:create-post,不再报错。查看执行结果,有输出日志文件:Modules-Blog-Console-CreatePostCommand-handle-1672371310.181-805184791.txt

图4

11、执行:php artisan schedule:run,响应:没有计划的命令准备好运行。


PS E:\wwwroot\laravel6-modules-demo> php artisan schedule:run
No scheduled commands are ready to run.


12、参考任务调度 – Artisan 命令调度,在 App\Console\Kernel 类的 schedule 方法中定义新的调度任务


    /**
     * Define the application's command schedule.
     *
     * @param  \Illuminate\Console\Scheduling\Schedule  $schedule
     * @return void
     */
    protected function schedule(Schedule $schedule)
    {
        // $schedule->command('inspire')
        //          ->hourly();
        $schedule->command('blog:create-post')->everyMinute(); // 每分钟执行一次任务
    }


13、执行 schedule:run 命令 ,执行成功,且成功生成对应的日志文件。如图5
执行 schedule:run 命令 ,执行成功,且成功生成对应的日志文件

图5



PS E:\wwwroot\laravel6-modules-demo> php artisan schedule:run
Running scheduled command: "C:\php-7.4.27\php.exe" "artisan" blog:create-post > "NUL" 2>&1


14、但是,既然 command blog:create-post 是在模块中编写的,那么调度此 command 的 schedule 也应该在对应的模块中编写才是更为合适的实现。 15、参考:https://stackoverflow.com/questions/30456737/how-to-schedule-artisan-commands-in-a-package ,两种方案皆是可行的。还原第 12 步骤的实现。


    /**
     * Boot the application events.
     *
     * @return void
     */
    public function boot()
    {
        $this->registerTranslations();
        $this->registerConfig();
        $this->registerViews();
        $this->registerFactories();
        $this->loadMigrationsFrom(module_path($this->moduleName, 'Database/Migrations'));
        /*
        $this->app->booted(function () {
            $schedule = $this->app->make(Schedule::class);
            $schedule->command('blog:create-post')->everyMinute();
        });
        */
        // 在 Laravel 6.10 及以上版本中:
        $this->callAfterResolving(Schedule::class, function (Schedule $schedule) {
            $schedule->command('blog:create-post')->everyMinute();
        });
    }




PS E:\wwwroot\laravel6-modules-demo> php artisan schedule:run
Running scheduled command: "C:\php-7.4.27\php.exe" "artisan" blog:create-post > "NUL" 2>&1
PS E:\wwwroot\laravel6-modules-demo> php artisan schedule:run
Running scheduled command: "C:\php-7.4.27\php.exe" "artisan" blog:create-post > "NUL" 2>&1


]]>
https://www.shuijingwanwq.com/2023/01/07/7330/feed/ 0
在 Laravel 8 中的模块化示例实现 https://www.shuijingwanwq.com/2022/01/25/5821/ https://www.shuijingwanwq.com/2022/01/25/5821/#respond Tue, 25 Jan 2022 01:40:39 +0000 https://www.shuijingwanwq.com/?p=5821 浏览量: 227 1、在 GitHub 中搜索:laravel module,选择第一个结果:nWidart / laravel-modules。其支持 Laravel 中的模块管理。 2、参考网址:https://nicolaswidart.com/blog/writing-modular-applications-with-laravel-modules 。为什么要使用这个包,使用 laravel-modules 编写模块化应用程序。当涉及到编写更复杂、更大的应用程序时,发现 laravel 的默认结构很麻烦而且不理想。 3、要通过 Composer 安装,请运行以下命令。如图1
要通过 Composer 安装,请运行以下命令

图1



PS E:\wwwroot\laravel-modules-demo> composer require nwidart/laravel-modules
Using version ^8.2 for nwidart/laravel-modules
./composer.json has been updated
Running composer update nwidart/laravel-modules
Loading composer repositories with package information
Updating dependencies
Lock file operations: 1 install, 0 updates, 0 removals
  - Locking nwidart/laravel-modules (8.2.0)
Writing lock file
Installing dependencies from lock file (including require-dev)
Package operations: 1 install, 0 updates, 0 removals
  - Downloading nwidart/laravel-modules (8.2.0)
  - Installing nwidart/laravel-modules (8.2.0): Extracting archive
Package swiftmailer/swiftmailer is abandoned, you should avoid using it. Use symfony/mailer instead.
Generating optimized autoload files
> Illuminate\Foundation\ComposerScripts::postAutoloadDump
> @php artisan package:discover --ansi
Discovered Package: facade/ignition
Discovered Package: fruitcake/laravel-cors
Discovered Package: laravel/sail
Discovered Package: laravel/sanctum
Discovered Package: laravel/tinker
Discovered Package: nesbot/carbon
Discovered Package: nunomaduro/collision
Discovered Package: nwidart/laravel-modules
Package manifest generated successfully.
78 packages you are using are looking for funding.
Use the `composer fund` command to find out more!
> @php artisan vendor:publish --tag=laravel-assets --ansi --force
No publishable resources for tag [laravel-assets].
Publishing complete.


4、运行以下命令发布包的配置文件


PS E:\wwwroot\laravel-modules-demo> php artisan vendor:publish --provider="Nwidart\Modules\LaravelModulesServiceProvider"
Copied File [\vendor\nwidart\laravel-modules\config\config.php] To [\config\modules.php]
Publishing complete.


5、默认情况下,模块类不会自动加载。您可以使用 psr-4 自动加载模块。编辑 composer.json,然后运行:composer dump-autoload。如图2
默认情况下,模块类不会自动加载。您可以使用 psr-4 自动加载模块。编辑 composer.json,然后运行:composer dump-autoload

图2



    "autoload": {
        "psr-4": {
            "App\\": "app/",
            "Modules\\": "Modules/",
            "Database\\Factories\\": "database/factories/",
            "Database\\Seeders\\": "database/seeders/"
        }
    },




PS E:\wwwroot\laravel-modules-demo> composer dump-autoload
Generating optimized autoload files
> Illuminate\Foundation\ComposerScripts::postAutoloadDump
> @php artisan package:discover --ansi
Discovered Package: facade/ignition
Discovered Package: fruitcake/laravel-cors
Discovered Package: laravel/sail
Discovered Package: laravel/sanctum
Discovered Package: laravel/tinker
Discovered Package: nesbot/carbon
Discovered Package: nunomaduro/collision
Discovered Package: nwidart/laravel-modules
Package manifest generated successfully.
Generated optimized autoload files containing 5106 classes
PS E:\wwwroot\laravel-modules-demo>


6、参考文档:https://nwidart.com/laravel-modules/v6/introduction ,快速开启一个示例,使用 php artisan module:make Blog 生成你的第一个模块。 将生成以下结构。由于文档的版本是针对 v6 的,而现在程序的最新版本是 v8,因此,目录结构有所出入。如图3
使用 php artisan module:make Blog 生成你的第一个模块。 将生成以下结构。由于文档的版本是针对 v6 的,而现在程序的最新版本是 v8,因此,目录结构有所出入

图3



PS E:\wwwroot\laravel-modules-demo> php artisan module:make Blog
Created : E:\wwwroot\laravel-modules-demo\Modules/Blog/module.json
Created : E:\wwwroot\laravel-modules-demo\Modules/Blog/Routes/web.php
Created : E:\wwwroot\laravel-modules-demo\Modules/Blog/Routes/api.php
Created : E:\wwwroot\laravel-modules-demo\Modules/Blog/Resources/views/index.blade.php
Created : E:\wwwroot\laravel-modules-demo\Modules/Blog/Resources/views/layouts/master.blade.php
Created : E:\wwwroot\laravel-modules-demo\Modules/Blog/Config/config.php
Created : E:\wwwroot\laravel-modules-demo\Modules/Blog/composer.json
Created : E:\wwwroot\laravel-modules-demo\Modules/Blog/Resources/assets/js/app.js
Created : E:\wwwroot\laravel-modules-demo\Modules/Blog/Resources/assets/sass/app.scss
Created : E:\wwwroot\laravel-modules-demo\Modules/Blog/webpack.mix.js
Created : E:\wwwroot\laravel-modules-demo\Modules/Blog/package.json
Created : E:/wwwroot/laravel-modules-demo/Modules/Blog/Database/Seeders/BlogDatabaseSeeder.php
Created : E:/wwwroot/laravel-modules-demo/Modules/Blog/Providers/BlogServiceProvider.php
Created : E:/wwwroot/laravel-modules-demo/Modules/Blog/Providers/RouteServiceProvider.php
Created : E:/wwwroot/laravel-modules-demo/Modules/Blog/Http/Controllers/BlogController.php
Module [Blog] created successfully.


7、默认情况下,当您创建新模块时,该命令会自动添加一些资源,例如控制器、种子类、服务提供者等。如果你不想要这些,你可以添加 –plain 标志,生成一个普通的模块。将生成以下结构。如图4
默认情况下,当您创建新模块时,该命令会自动添加一些资源,例如控制器、种子类、服务提供者等。如果你不想要这些,你可以添加 --plain 标志,生成一个普通的模块。将生成以下结构

图4



PS E:\wwwroot\laravel-modules-demo> php artisan module:make Auth -p
Created : E:\wwwroot\laravel-modules-demo\Modules/Auth/module.json
Module [Auth] created successfully.


]]>
https://www.shuijingwanwq.com/2022/01/25/5821/feed/ 0
在 Yii 2.0 中微信消息加解密的引入的重构(调整类库命名方式符合 PSR-4 标准,再使用 Yii 官方的自动加载器来自动加载这些类) https://www.shuijingwanwq.com/2021/07/02/5015/ https://www.shuijingwanwq.com/2021/07/02/5015/#respond Fri, 02 Jul 2021 08:26:58 +0000 https://www.shuijingwanwq.com/?p=5015 浏览量: 85

1、之前的某位同事的实现,下载微信示例代码,添加至当前应用的 /vender/wx_biz_msg_crypt 目录下,再在 init() 方法中 require。如图1

之前的某位同事的实现,下载微信示例代码,添加至当前应用的 /vender/wx_biz_msg_crypt 目录下,再在 init() 方法中 require

图1

<?php
 
namespace frontend\controllers;
 
use Yii;
use frontend\models\http\wx_auth\AccessToken as HttpWxAuthAccessToken;
use WXBizMsgCrypt;
use yii\filters\AccessControl;
use yii\helpers\Json;
use yii\rest\Controller;
use yii\web\NotFoundHttpException;
use yii\web\ServerErrorHttpException;
 
class WxMsgEventController extends Controller
{
    public $redis;
 
    /**
     * {@inheritdoc}
     */
    public function behaviors()
    {
        return [
            'access' => [
                'class' => AccessControl::className(),
                'only' => ['logout', 'signup'],
                'rules' => [
                    [
                        'actions' => ['signup'],
                        'allow' => true,
                        'roles' => ['?'],
                    ],
                    [
                        'actions' => ['logout'],
                        'allow' => true,
                        'roles' => ['@'],
                    ],
                ],
            ],
        ];
    }
 
    public function init()
    {
        parent::init();
        require __DIR__ . '/../vendor/wx_biz_msg_crypt/wxBizMsgCrypt.php';
        $this->redis = Yii::$app->redis;
 
    }
}
 

2、在 GitHab 中搜索:微信加解密,并未发现微信官方的 Git 包,确认无法基于 Composer 安装。

3、参考 引入第三方代码(Working with Third-Party Code),使用下载的类库(Using Downloaded Libraries):https://www.yiiframework.com/doc/guide/2.0/zh-cn/tutorial-yii-integration#using-downloaded-libs。

4、参考:https://github.com/PizzaLiu/PHP-FIG/blob/master/PSR-4-autoloader-cn.md 。例子:\Aura\Web\Response\Status。决定调整类库命名方式符合 PSR-4 标准,再使用 Yii 官方的自动加载器来自动加载这些类。将 文件名 分别重命名为与 类名 相同,且大小写保持一致。

5、编辑文件:/frontend/vendor/src/wx-biz-msg-crypt/WXBizMsgCrypt.php,声明命名空间:wx\biz\msg\crypt,include_once 全部删除,其他文件也如法炮制。

<?php
namespace wx\biz\msg\crypt;
 
/**
 * 对公众平台发送给公众账号的消息加解密示例代码.
 *
 * @copyright Copyright (c) 1998-2014 Tencent Inc.
 */
 
/**
 * 1.第三方回复加密消息给公众平台;
 * 2.第三方收到公众平台发送的消息,验证消息的安全性,并对消息进行解密。
 */
class WXBizMsgCrypt
{
}

6、需要着重注意的是文件:PKCS7Encoder.php 中存在 2 个类,需要拆分为文件:PKCS7Encoder.php、Prpcrypt.php。文件基目录为小写字母,以中横杠连接。如图2

需要着重注意的是文件:PKCS7Encoder.php 中存在 2 个类,需要拆分为文件:PKCS7Encoder.php、Prpcrypt.php。文件基目录为小写字母,以中横杠连接。

图2

7、给根命名空间声明一下根路径别名,编辑应用配置文件:/frontend/config/main.php。命名空间前缀为小写字母,以正斜杠连接。


return [
    'aliases' => [
        '@wx/biz/msg/crypt' => '@frontend/vendor/wx-biz-msg-crypt/src',
    ],
]


8、之前的某位同事的实现文件,再次编辑,引用的调整,use wx\biz\msg\crypt\WXBizMsgCrypt;,再在 init() 方法中 去掉 require。

<?php
 
 
namespace frontend\controllers;
 
use Yii;
use frontend\models\http\wx_auth\AccessToken as HttpWxAuthAccessToken;
use wx\biz\msg\crypt\WXBizMsgCrypt;
use yii\filters\AccessControl;
use yii\helpers\Json;
use yii\rest\Controller;
use yii\web\NotFoundHttpException;
use yii\web\ServerErrorHttpException;
 
class WxMsgEventController extends Controller
{
    public $redis;
 
    /**
     * {@inheritdoc}
     */
    public function behaviors()
    {
        return [
            'access' => [
                'class' => AccessControl::className(),
                'only' => ['logout', 'signup'],
                'rules' => [
                    [
                        'actions' => ['signup'],
                        'allow' => true,
                        'roles' => ['?'],
                    ],
                    [
                        'actions' => ['logout'],
                        'allow' => true,
                        'roles' => ['@'],
                    ],
                ],
            ],
        ];
    }
 
    public function init()
    {
        parent::init();
        $this->redis = Yii::$app->redis;
 
    }
 
    /**
     * 获取验证票据(接收微信服务器推送)
     */
    public function actionTicket()
    {
        //try {
            $request = Yii::$app->request;
            $requestRawBody = $request->getRawBody();
            $requestQueryParams = $request->getQueryParams();
            file_put_contents(Yii::getAlias('@runtime') . '/componentVerifyTicketQueryParams.txt', print_r($requestQueryParams, true), LOCK_EX);
            file_put_contents(Yii::getAlias('@runtime') . '/componentVerifyTicketRawBody.txt', print_r($requestRawBody, true), LOCK_EX);
 
            $appId = Yii::$app->params['wxOpen']['component']['appId'];
            $appSecret = Yii::$app->params['wxOpen']['component']['appSecret'];
            $token = Yii::$app->params['wxOpen']['component']['token'];
            $encodingAesKey = Yii::$app->params['wxOpen']['component']['symmetricKey'];
 
            $msg = '';
            $pc = new WXBizMsgCrypt($token, $encodingAesKey, $appId);
            // 解密 xml 数据
            $errCode = $pc->decryptMsg($requestQueryParams['msg_signature'], $requestQueryParams['timestamp'], $requestQueryParams['nonce'], $requestRawBody, $msg);
            file_put_contents(Yii::getAlias('@runtime') . '/componentVerifyTicketDecrypt.txt', print_r($errCode, true), LOCK_EX);
            // 解密成功
            if ($errCode == 0) {
                $ticketData = $this->xmlToArray($msg);
                if (isset($ticketData['ComponentVerifyTicket'])) {
                    $redisCommandkeyPrefix = Yii::$app->params['redisCommand']['keyPrefix'];
                    $componentVerifyTicketKey = $redisCommandkeyPrefix . $ticketData['AppId'] . ':component_verify_ticket';
                    $this->redis->set($componentVerifyTicketKey, $ticketData['ComponentVerifyTicket']);
                    // 获取第三方平台component_access_token
                    $this->getComponentAccessToken($appId, $appSecret);
                }
            }
            file_put_contents(Yii::getAlias('@runtime') . '/componentVerifyTicketMsgXml.txt', print_r($msg, true), LOCK_EX);
            /*
        } catch (\Throwable $th) {
            file_put_contents(Yii::getAlias('@runtime') . '/componentVerifyTicketError.txt', print_r($th->getMessage(), true), LOCK_EX);
        }
            */
        exit('success');
    }
 

9、将所有文件的编码调整为:UTF-8,重新运行程序,查看解密出的数据文件:componentVerifyTicketMsgXml.txt。符合预期。如图3

将所有文件的编码调整为:UTF-8,重新运行程序,查看解密出的数据文件:componentVerifyTicketMsgXml.txt。符合预期

图3

<xml><AppId><![CDATA[wxd98c58b273d21bdf]]></AppId>
<CreateTime>1625124291</CreateTime>
<InfoType><![CDATA[component_verify_ticket]]></InfoType>
<ComponentVerifyTicket><![CDATA[ticket@@@PaPM2hcjK8DPPkW_ZzbaR4DCQtirExq932-BBnxhQg19QWJtIKm3Io0TXsWMqcdv-18WnjkWSiSLNPSoXmqGSA]]></ComponentVerifyTicket>
</xml>

 

]]>
https://www.shuijingwanwq.com/2021/07/02/5015/feed/ 0