Phalcon搭建多模块框架一:定义基本目录结构和基本配置
前言:入职新公司,公司使用的是Phalcon框架,以前没接触过,看公司的项目都是单模块,并且写的很乱(例如在控制器文件中使用require来引入model文件,在控制器文件写函数等)所以想自己搭建一套多模块框架,学习途径主要是官方文档和cphalcon源码,由于是初次学习使用该框架,所以难免有错误和不合理的地方,欢迎指正。
Phalcon是高性能低耦合的框架,你可以根据自己的喜好搭建不同的目录结构,下面的目录结构只是一种参考。使用之前请先对apache或者nginx重写url规则。
下面根据这个目录结构搭建一个基础的多模块框架:
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!’
至此,一个简单的多模块搭建完成,后续将丰富和完善各种功能
下一篇: 理解 maven 多模块项目依赖关系