欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Phalcon搭建多模块框架一:定义基本目录结构和基本配置

程序员文章站 2024-02-03 20:50:46
...

前言:入职新公司,公司使用的是Phalcon框架,以前没接触过,看公司的项目都是单模块,并且写的很乱(例如在控制器文件中使用require来引入model文件,在控制器文件写函数等)所以想自己搭建一套多模块框架,学习途径主要是官方文档和cphalcon源码,由于是初次学习使用该框架,所以难免有错误和不合理的地方,欢迎指正。

Phalcon是高性能低耦合的框架,你可以根据自己的喜好搭建不同的目录结构,下面的目录结构只是一种参考。使用之前请先对apache或者nginx重写url规则。
Phalcon搭建多模块框架一:定义基本目录结构和基本配置
下面根据这个目录结构搭建一个基础的多模块框架:
1、在public目录创建入口文件index.php,

<?php
/**
 * @desc 入口文件
 * @author zhaoyang
 * @date 2018年5月3日 下午5:16:27
 */
// 检查版本,搭建用到php7一些新特性
version_compare(PHP_VERSION, '7.0.0', '>') || die('Require PHP > 7.0.0 !');
extension_loaded('phalcon') || die('Please open the Phalcon extension !');

use \Phalcon\Mvc\Application;

error_reporting(E_ALL & ~E_NOTICE);

// 设置时区
date_default_timezone_set('Asia/Shanghai');

//重新命名文件分隔符,建议路径后面加上分隔符
define('DS', DIRECTORY_SEPARATOR);

// 应用程序名称(应用程序所在目录名)
define('APP_NAME', 'app');

// *命名空间
define('APP_NAMESPACE', 'App');

// 项目根目录
define('BASE_PATH', dirname(__DIR__) . DS);

// 应用程序所在目录
define('APP_PATH', BASE_PATH . APP_NAME . DS);

// 模块列表,这里是定义了前台home模块和后天admin模块
// @formatter:off
define('MODULE_ALLOW_LIST', ['home', 'admin']);
// @formatter:on

// 默认模块
define('DEFAULT_MODULE', 'home');

// 默认模块命名空间
define('DEFAULT_MODULE_NAMESPACE', APP_NAMESPACE . '\Home');

try {
    // 引入配置文件
    $config = require BASE_PATH . 'config/config.php';

    // 引入自动加载配置
    require BASE_PATH . 'config/loader.php';

    // 引入路由规则
    $routerRules = require BASE_PATH . 'config/routers.php';

    // 引入注册服务
    require BASE_PATH . 'config/services.php';

    // 处理请求
    $application = new Application($di);

    // 组装应用程序模块
    $modules = [ ];
    foreach (MODULE_ALLOW_LIST as $v) {
        $modules[$v] = [
            'className' => APP_NAMESPACE . '\\' . ucfirst($v) . '\Module',
            'path' => APP_PATH . $v . '/Module.php'
        ];
    }
    // 加入模块分组配置
    $application->registerModules($modules);

    // 输出请求内容
    echo $application->handle()->getContent();
} catch (\Throwable $e) {
    // 暂时不处理错误
    $error = 'PhalconException: [所在文件:' . $e->getFile() . '] [所在行:' . $e->getLine() . '] [错误码:' . $e->getCode() . '] [错误消息:' . $e->getMessage() . '] [异常追踪信息:' . $e->getTraceAsString() . ']';
    echo $error;
}

2、在config目录下创建公共配置文件config.php,暂时不做任何配置

<?php
/**
 * @desc 全局配置文件
 * @author zhaoyang
 * @date 2018年5月3日 下午7:54:47
 */
return [];

3、在config目录下创建自动加载配置文件loader.php

<?php
use Phalcon\Loader;

$loader = new Loader();

$loader->registerNamespaces([
    'Common' => BASE_PATH . 'common/',
    'Library\\Extensions' => BASE_PATH . 'library/extensions/',
    'Library\\Plugins' => BASE_PATH . 'library/plugins/',
    'Library\\Tools' => BASE_PATH . 'library/tools/',
    'Library\\Vendor' => BASE_PATH . 'library/vendor/'
])->register();

4、在config目录下创建路由规则配置文件routers.php,这里定义了默认的路由和模块路由,可以有以下多种方式访问:
1)域名(注:访问默认模块的默认控制器的默认方法)
2)域名/控制器名(注:访问默认模块的指定控制器的默认方法)
3)域名/控制器名/方法名(注:访问默认模块的指定控制器的指定方法)
4)域名/控制器名/方法名/参数/值(注:访问默认模块的指定控制器的指定方法并携带参数)
5)域名/模块名(注:访问指定模块的默认控制器的默认方法)
6)域名/模块名/控制器名(注:访问指定模块的指定控制器的默认方法)
7)域名/模块名/控制器名/方法名(注:访问指定模块的指定控制器的指定方法)
8)域名/模块名/控制器名/方法名/参数/值(注:访问指定模块的指定控制器的指定方法并携带参数)

<?php
/**
 * @desc 路由规则
 * @author zhaoyang
 * @date 2018年5月3日 下午7:59:20
 */
// @formatter:off
defined('MODULE_ALLOW_LIST') || define('MODULE_ALLOW_LIST', ['home']);
//@formatter:on
defined('DEFAULT_MODULE') || define('DEFAULT_MODULE', MODULE_ALLOW_LIST[0]);
defined('DEFAULT_MODULE_NAMESPACE') || define('DEFAULT_MODULE_NAMESPACE', APP_NAMESPACE . '\\' . ucfirst(MODULE_ALLOW_LIST['0']));
$defaultRouters = [
    '/' => [
        'namespace' => DEFAULT_MODULE_NAMESPACE . '\\Controllers',
        'module' => DEFAULT_MODULE,
        'controller' => 'index',
        'action' => 'index'
    ],
    '/:controller' => [
        'namespace' => DEFAULT_MODULE_NAMESPACE . '\\Controllers',
        'module' => DEFAULT_MODULE,
        'controller' => 1,
        'action' => 'index'
    ],
    '/:controller/:action' => [
        'namespace' => DEFAULT_MODULE_NAMESPACE . '\\Controllers',
        'module' => DEFAULT_MODULE,
        'controller' => 1,
        'action' => 2
    ],
    '/:controller/:action/:params' => [
        'namespace' => DEFAULT_MODULE_NAMESPACE . '\\Controllers',
        'module' => DEFAULT_MODULE,
        'controller' => 1,
        'action' => 2,
        'params' => 3
    ]
];

$routers = [ ];
foreach (MODULE_ALLOW_LIST as $v) {
    $vUcfirst = ucfirst($v);
    $routers['/' . $v] = [
        'namespace' => APP_NAMESPACE . '\\' . $vUcfirst . '\\Controllers',
        'module' => $v,
        'controller' => 'Index',
        'action' => 'index'
    ];
    $routers['/' . $v . '/:controller'] = [
        'namespace' => APP_NAMESPACE . '\\' . $vUcfirst . '\\Controllers',
        'module' => $v,
        'controller' => 1,
        'action' => 'index'
    ];
    $routers['/' . $v . '/:controller/:action'] = [
        'namespace' => APP_NAMESPACE . '\\' . $vUcfirst . '\\Controllers',
        'module' => $v,
        'controller' => 1,
        'action' => 2
    ];
    $routers['/' . $v . '/:controller/:action/:params'] = [
        'namespace' => APP_NAMESPACE . '\\' . $vUcfirst . '\\Controllers',
        'module' => $v,
        'controller' => 1,
        'action' => 2,
        'params' => 3
    ];
}
return array_merge($defaultRouters, $routers);

5、在config目录下创建注册服务文件services.php
有多种注册方式,一般用set()方法和setShared()方法,setShared()方法是注册单例模式服务,set()方法有三个参数,如果第三个参数设置为true,则与setShared()方法一样是单例模式,其实在源码中setShared()方法也是调用set()方法并设置第三个参数为true。
一般需要动态传参的服务使用set()方法,不需要动态传参的使用setShared()方法
(注:这是编者自己的总结,如有错误欢迎指正)

<?php
/**
 * @desc 注册服务
 * @author zhaoyang
 * @date 2018年5月3日 下午8:01:34
 */

use Phalcon\Config;
use Phalcon\DI;
use Phalcon\DI\FactoryDefault;
use Phalcon\Mvc\Dispatcher;
use Phalcon\Mvc\Router;
use Phalcon\Mvc\View;

$di = new FactoryDefault();

/**
 * @desc 注册调度器服务
 * @author zhaoyang
 * @date 2018年5月3日 下午8:38:34
 */
$di->setShared('dispatcher', function () {
    $config = $this->getConfig();
    $dispatcher = new Dispatcher();
    $defaultNamespace = $config->module_default_namespaces ?? DEFAULT_MODULE_NAMESPACE . '\\Controllers';
    $dispatcher->setDefaultNamespace($defaultNamespace);
    return $dispatcher;
});

/**
 * @desc 注册配置服务
 * @author zhaoyang
 * @date 2018年5月3日 下午8:38:53
 */
$di->setShared('config', function () use ($config) {
    return new Config($config);
});

/**
 * @desc 注册路由服务
 * @author zhaoyang
 * @date 2018年5月3日 下午8:39:06
 */
$di->setShared('router', function () use ($routerRules) {
    $router = new Router();
    // 自动删除末尾斜线
    $router->removeExtraSlashes(true);
    foreach ($routerRules as $k => $v) {
        $router->add($k, $v);
    }
    return $router;
});

/**
 * @desc 注册视图服务
 * @author zhaoyang
 * @date 2018年5月3日 下午10:52:37
 */
$di->set('view', function () {
    $view = new View();
    $view->setViewsDir(APP_PATH . MODULE_NAME . '/views' . DS);
    return $view;
});

6、在app/home/config目录下创建模块配置文件config.php,它会合并覆盖公共配置

<?php
// 模块名称
defined('MODULE_NAME') || define('MODULE_NAME', 'home');
// 模块命名空间
defined('MODULE_NAMESPACE') || define('MODULE_NAMESPACE', APP_NAMESPACE . '\\Home');

return [
    // 模块名称
    'module_name' => MODULE_NAME,
    // 需要注册的模块命名空间
    'module_namespaces' => [
        MODULE_NAMESPACE . '\\Controllers' => APP_PATH . MODULE_NAME . '/controllers' . DS,
        MODULE_NAMESPACE . '\\Models' => APP_PATH . MODULE_NAME . '/models' . DS
    ],
    // 模块默认的命名空间
    'module_default_namespaces' => MODULE_NAMESPACE . '\\Controllers',
];

7、在app/home目录下创建多模块配置文件Module.php
该文件主要是注册自动加载和一些模块特定的服务,比如有的公共服务不满足,需要重写,或者该模块特有的服务,而公共服务中没有,可以在这里注册。
该类中主要有两个方法,registerAutoloaders()方法是注册自动加载的,比如控制器、模型等自动加载,registerServices()方法是注册和重写一些服务的。这里主要用于把公共配置文件和模块配置文件合并。

<?php
/**
 * @desc 模块配置
 * @author zhaoyang
 * @date 2018年5月3日 下午8:49:49
 */
namespace App\Home;

use Phalcon\DiInterface;
use Phalcon\Loader;
use Phalcon\Mvc\ModuleDefinitionInterface;
use Phalcon\Config\Adapter\Php as ConfigAdapterPhp;

class Module implements ModuleDefinitionInterface {

    // 模块配置文件目录
    private static $_configPath = __DIR__ . '/config/config.php';

    // 默认需要注册的命名空间
    private static $_defaultRegisterNamespaces = [
        __NAMESPACE__ . '\\Controllers' => __DIR__ . '/controllers/',
        __NAMESPACE__ . '\\Models' => __DIR__ . '/models/'
    ];

    public function registerAutoloaders(DiInterface $di = NULL) {
        $this->registerConfigService($di);
        $config = $di->getConfig();
        $loader = new Loader();
        $nameSpaces = isset($config->module_namespaces) ? $config->module_namespaces->toArray() : self::$_defaultRegisterNamespaces;
        $loader->registerNamespaces($nameSpaces)->register();
    }

    public function registerServices(DiInterface $di) {
        // 注册配置文件服务,合并主配置和模块配置
        $this->registerConfigService($di);
    }

    /**
     * @desc 注册配置服务
     * @author zhaoyang
     * @date 2018年5月3日 下午8:50:51
     */
    private function registerConfigService(DiInterface $di) {
        $config = $di->getConfig();
        $di->setShared('config', function () use ($config) {
            $moduleConfigPath = self::$_configPath;
            if (is_file($moduleConfigPath)) {
                $override = new ConfigAdapterPhp($moduleConfigPath);
                $config->merge($override);
            }
            return $config;
        });
    }
}

8、在app/home/controllers目录下创建首页控制器IndexController.php

<?php
/**
 * @desc 主页
 * @author zhaoyang
 * @date 2018年3月23日 上午10:11:38
 */
namespace App\Home\Controllers;

use Phalcon\Mvc\Controller;

class IndexController extends Controller {

    public function indexAction() {
        echo 'Hello World!';
        exit;
    }
}

9、这时访问域名或者域名/home/index/index即可看到’Hello World!’
Phalcon搭建多模块框架一:定义基本目录结构和基本配置
Phalcon搭建多模块框架一:定义基本目录结构和基本配置
Phalcon搭建多模块框架一:定义基本目录结构和基本配置
Phalcon搭建多模块框架一:定义基本目录结构和基本配置

至此,一个简单的多模块搭建完成,后续将丰富和完善各种功能