Phalcon搭建多模块框架十九:注册modelsMetadata服务

phalcon每次请求中第一次对模型操作时都会先去查询模型对应的表结构等相关元数据,类似于

SELECT IF(COUNT(*) > 0, 1, 0) FROM `INFORMATION_SCHEMA`.`TABLES` WHERE `TABLE_NAME` = 'ph_robots' AND `TABLE_SCHEMA` = DATABASE()
DESCRIBE `ph_robots`

。默认使用内存(memory)存储。但内存存储的元数据仅在请求期间缓存。当请求完成时,元数据作为请求的正常内存的一部分被释放。这一特性在开发阶段很好用,表结构有改动都会随时刷新,但是生产环境则非常耗性能。所以最好用别的适配器将元数据存储一段时间。phalcon提供多种适配器,例如files、memcache、redis、session等,这里建议使用memcache或redis,不建议使用files,因为文件存储,读写受磁盘影响,并且files不能设置过期时间。如果后期因为新需求需要改动表结构等,则只能删除缓存文件后模型才能获得新的表结构。
这里写图片描述
1、打开config/config.php添加models_metadata配置(全局设置默认使用memcache,开发阶段可以设为memory)

'models_metadata' => [ 
   'options' => [ 
        'adapter' => 'memcache',
        'unique_id' => DEFAULT_MODULE,
        'prefix' => DEFAULT_MODULE,
        'persistent' => true,
        'lifetime' => 3600
    ]
]

完整的config/config.php

<?php
/**
 * @desc 全局配置文件
 * @author zhaoyang
 * @date 2018年5月3日 下午7:54:47
 */
return [ 
    // 服务配置
    'services' => [ 
        // mysql数据库配置
        'db' => [ 
            'host' => 'localhost',
            'port' => 3306,
            'username' => 'root',
            'password' => '123456',
            'dbname' => 'phalcon',
            'charset' => 'utf8',
            // 是否记录执行的mysql语句
            'logged' => true,
            // 记录执行时间超过0秒的mysql语句
            'max_execute_time' => 0,
            // 比较时间到小数点后几位
            'scale' => 5,
            'log_path' => BASE_PATH . 'runtime/mysql/{Y/m/d}/{YmdH}.log'
        ],
        // 调度器配置
        'dispatcher' => [ 
            // 处理 Not-Found错误配置
            'notfound' => [ 
                // 错误码及错误提示
                'status_code' => 404,
                'message' => 'Not Found',
                // 错误跳转的页面
                'namespace' => DEFAULT_MODULE_NAMESPACE . '\\Controllers',
                'controller' => 'error',
                'action' => 'error404'
            ]
        ],
        // volt引擎相关配置
        'view_engine_volt' => [ 
            // 编译模板目录
            'compiled_path' => BASE_PATH . 'runtime/' . DEFAULT_MODULE . '/compiled/volt' . DS,
            // 是否实时编译
            'compile_always' => false,
            // 附加到已编译的PHP文件的扩展名
            'compiled_extension' => '.php',
            // 使用这个替换目录分隔符
            'compiled_separator' => '%%',
            // 是否要检查在模板文件和它的编译路径之间是否存在差异
            'stat' => true,
            // 模板前缀
            'prefix' => '',
            // 支持HTML的全局自动转义
            'autoescape' => false
        ],
        // 模板相关配置
        'view' => [ 
            // 模板后缀
            'view_suffix' => 'volt,phtml',
            // 模板路径
            'view_path' => APP_PATH . DEFAULT_MODULE . '/views' . DS,
            // 模板引擎,暂时支持viewEngineVolt or viewEnginePhp,与模板后缀一一对应
            'view_service' => 'viewEngineVolt,viewEnginePhp'
        ],
        // 过滤器设置
        'filter' => [ 
            // 过滤类型,支持string、trim、absint、int、email、float、int!、float!、alphanum、striptags、lower、upper、url、special_chars
            'default_filter' => 'string,trim'
        ],
        // 文件日志,formatter常用line,adapter常用file
        'logger' => [ 
            'line' => [ 
                'format' => '[%date%][%type%] %message%',
                'date_format' => 'Y-m-d H:i:s'
            ],
            'file' => [ 
                'alert' => BASE_PATH . 'runtime/' . DEFAULT_MODULE . '/logs/alert/{Y/m/d}/{YmdH}.log',
                'critical' => BASE_PATH . 'runtime/' . DEFAULT_MODULE . '/logs/critical/{Y/m/d}/{YmdH}.log',
                'debug' => BASE_PATH . 'runtime/' . DEFAULT_MODULE . '/logs/debug/{Y/m/d}/{YmdH}.log',
                'error' => BASE_PATH . 'runtime/' . DEFAULT_MODULE . '/logs/error/{Y/m/d}/{YmdH}.log',
                'emergency' => BASE_PATH . 'runtime/' . DEFAULT_MODULE . '/logs/emergency/{Y/m/d}/{YmdH}.log',
                'info' => BASE_PATH . 'runtime/' . DEFAULT_MODULE . '/logs/info/{Y/m/d}/{YmdH}.log',
                'notice' => BASE_PATH . 'runtime/' . DEFAULT_MODULE . '/logs/notice/{Y/m/d}/{YmdH}.log',
                'warning' => BASE_PATH . 'runtime/' . DEFAULT_MODULE . '/logs/warning/{Y/m/d}/{YmdH}.log'
            ]
        ],
        // session配置
        'session' => [ 
            // 是否自动开启 SESSION
            'auto_start' => true,
            'options' => [ 
                'adapter' => 'files',
                'unique_id' => DEFAULT_MODULE
            ]
            // @formatter:off
            /* // phalcon提供了四种适配器,分别是files、memcache、redis、libmemcached
            'options' => [
                'adapter'    => 'memcache',
                'unique_id' => DEFAULT_MODULE,
                'prefix' => DEFAULT_MODULE,
                'persistent' => true,
                'lifetime' => 3600
            ],
            'options' => [
                'adapter'    => 'redis',
                'unique_id' => DEFAULT_MODULE,
                'prefix' => DEFAULT_MODULE,
                'auth' => '',
                'persistent' => false,
                'lifetime' => 3600,
                'index' => 1
            ] */
            // @formatter:on
        ],
        // 加密配置
        'crypt' => [ 
            // 加密秘钥
            'key' => DEFAULT_MODULE,
            // 填充方式,默认是0(PADDING_DEFAULT),1(PADDING_ANSI_X_923)、2(PADDING_PKCS7)、3(PADDING_ISO_10126)、4(PADDING_ISO_IEC_7816_4)、5(PADDING_ZERO)、6(PADDING_SPACE)
            'padding' => '',
            // 加密方法,默认是"aes-256-cfb"
            'cipher' => ''
        ],
        // cookies配置
        'cookies' => [ 
            // 是否使用加密,使用加密必须要设置crypt 的key值
            'use_encryption' => true
        ],
        // 缓存配置
        'cache' => [ 
            'frontend' => [ 
                // 数据处理方式,支持data(序列化)、json、base64、none、output、igbinary、msgpack
                'data' => [ 
                    'lifetime' => 172800
                ]
            ],
            'backend' => [ 
                // 数据缓存方式,支持memcache、file、redis、mongo、apc、apcu、libmemcached、memory、xcache
                'file' => [ 
                    'cache_dir' => BASE_PATH . 'runtime/' . DEFAULT_MODULE . '/cache/',
                    // 对保存的键名进行md5加密
                    'safekey' => true,
                    'prefix' => ''
                ],
                'memcache' => [ 
                    'host' => 'localhost',
                    'port' => '11211',
                    'persistent' => false,
                    'prefix' => '',
                    // 默认情况下禁用对缓存键的跟踪
                    'stats_key' => ''
                ],
                'redis' => [ 
                    'host' => '127.0.0.1',
                    'port' => 6379,
                    'auth' => '',
                    'persistent' => false,
                    'prefix' => '',
                    'stats_key' => '',
                    'index' => 0
                ]
            ]
        ],
        // 模型元数据缓存配置
        'models_metadata' => [ 
            'options' => [ 
                'adapter' => 'memcache',
                'unique_id' => DEFAULT_MODULE,
                'prefix' => DEFAULT_MODULE,
                'persistent' => true,
                'lifetime' => 3600
            ]
            // @formatter:off
            /* 'options' => [
                // 适配器,默认使用memory(内存),还支持apc、apcu、files、libmemcached、memcache、redis、session、xcache
                'adapter' => 'files',
                'meta_data_dir' => BASE_PATH . 'runtime/' . DEFAULT_MODULE . '/models_metadata/'
            ],
            'options' => [
                'adapter'    => 'memcache',
                'unique_id' => DEFAULT_MODULE,
                'prefix' => DEFAULT_MODULE,
                'persistent' => true,
                'lifetime' => 3600
            ],
            'options' => [
                'adapter' => 'memory',
            ],
            'options' => [
                'adapter'    => 'redis',
                'unique_id' => DEFAULT_MODULE,
                'prefix' => DEFAULT_MODULE,
                'auth' => '',
                'persistent' => false,
                'lifetime' => 3600,
                'index' => 1
            ],
            'options' => [
                'adapter' => 'session',
                'prefix' => DEFAULT_MODULE,
            ] */
            // @formatter:on
        ]
    ]

];

2、打开home模块下的配置文件app/home/config/config.php(home模块下设置使用file,便于此次查看数据,但不推荐使用此配置)

'models_metadata' => [
   'options' => [
        // 适配器,默认使用memory(内存),还支持apc、apcu、files、libmemcached、memcache、redis、session、xcache
        'adapter' => 'files',
        'meta_data_dir' => BASE_PATH . 'runtime/' . MODULE_NAME . '/models_metadata/'
    ]
]

完整的app/home/config/config.php

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

return [ 
    // 需要注册的模块命名空间
    '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',
    // 服务配置
    'services' => [ 
        // 调度器配置
        'dispatcher' => [ 
            // 处理 Not-Found错误配置
            'notfound' => [ 
                // 错误码及错误提示
                'status_code' => 404,
                'message' => 'Not Found',
                // 错误跳转的页面
                'namespace' => MODULE_NAMESPACE . '\\Controllers',
                'controller' => 'error',
                'action' => 'error404'
            ]
        ],
        // volt引擎相关配置
        'view_engine_volt' => [ 
            // 编译模板目录
            'compiled_path' => BASE_PATH . 'runtime/' . MODULE_NAME . '/compiled/volt' . DS,
            // 是否实时编译
            'compile_always' => false,
            // 附加到已编译的PHP文件的扩展名
            'compiled_extension' => '.php',
            // 使用这个替换目录分隔符
            'compiled_separator' => '%%',
            // 是否要检查在模板文件和它的编译路径之间是否存在差异
            'stat' => true,
            // 模板前缀
            'prefix' => '',
            // 支持HTML的全局自动转义
            'autoescape' => false
        ],
        // 模板相关配置
        'view' => [ 
            // 模板后缀
            'view_suffix' => 'volt,phtml',
            // 模板路径
            'view_path' => APP_PATH . MODULE_NAME . '/views' . DS,
            // 模板引擎,暂时支持viewEngineVolt or viewEnginePhp,与模板后缀一一对应
            'view_service' => 'viewEngineVolt,viewEnginePhp'
        ],
        // 过滤器设置
        'filter' => [ 
            // 过滤类型,支持string、trim、absint、int、email、float、int!、float!、alphanum、striptags、lower、upper、url、special_chars
            'default_filter' => 'string,trim'
        ],
        // 文件日志,formatter常用line,adapter常用file
        'logger' => [ 
            'line' => [ 
                'format' => '[%date%][%type%] %message%',
                'dateFormat' => 'Y-m-d H:i:s'
            ],
            'file' => [ 
                'alert' => BASE_PATH . 'runtime/' . MODULE_NAME . '/logs/alert/{Y/m/d}/{YmdH}.log',
                'critical' => BASE_PATH . 'runtime/' . MODULE_NAME . '/logs/critical/{Y/m/d}/{YmdH}.log',
                'debug' => BASE_PATH . 'runtime/' . MODULE_NAME . '/logs/debug/{Y/m/d}/{YmdH}.log',
                'error' => BASE_PATH . 'runtime/' . MODULE_NAME . '/logs/error/{Y/m/d}/{YmdH}.log',
                'emergency' => BASE_PATH . 'runtime/' . MODULE_NAME . '/logs/emergency/{Y/m/d}/{YmdH}.log',
                'info' => BASE_PATH . 'runtime/' . MODULE_NAME . '/logs/info/{Y/m/d}/{YmdH}.log',
                'notice' => BASE_PATH . 'runtime/' . MODULE_NAME . '/logs/notice/{Y/m/d}/{YmdH}.log',
                'warning' => BASE_PATH . 'runtime/' . MODULE_NAME . '/logs/warning/{Y/m/d}/{YmdH}.log'
            ]
        ],
        'session' => [ 
            'auto_start' => true,
            'options' => [ 
                'adapter' => 'memcache',
                'unique_id' => MODULE_NAME,
                'prefix' => MODULE_NAME,
                'persistent' => true,
                'lifetime' => 3600
            ]
        ],
        // 加密配置
        'crypt' => [ 
            // 加密秘钥
            'key' => MODULE_NAME,
            // 填充方式,默认是0(PADDING_DEFAULT),1(PADDING_ANSI_X_923)、2(PADDING_PKCS7)、3(PADDING_ISO_10126)、4(PADDING_ISO_IEC_7816_4)、5(PADDING_ZERO)、6(PADDING_SPACE)
            'padding' => '',
            // 加密方法,默认是"aes-256-cfb"
            'cipher' => ''
        ],
        // cookies配置
        'cookies' => [ 
            // 是否使用加密,使用加密必须要设置crypt 的key值
            'use_encryption' => true
        ],
        // 缓存配置
        'cache' => [ 
            'backend' => [ 
                // 数据缓存方式,支持memcache、file、redis、mongo、apc、apcu、libmemcached、memory、xcache
                'file' => [ 
                    'cache_dir' => BASE_PATH . 'runtime/' . MODULE_NAME . '/cache/'
                ]
            ]
        ],
        // 模型元数据缓存配置
        'models_metadata' => [
            'options' => [
                // 适配器,默认使用memory(内存),还支持apc、apcu、files、libmemcached、memcache、redis、session、xcache
                'adapter' => 'files',
                'meta_data_dir' => BASE_PATH . 'runtime/' . MODULE_NAME . '/models_metadata/'
            ]
        ]
    ]
];

3、打开config/services.php注册modelsMetadata服务

$di->setShared('modelsMetadata', function () {
    $modelsMetadataConfig = $this->getConfig()->services->models_metadata;
    $backendConfig = $this->getConfig()->services->cache->backend;
    $optionsArr = $modelsMetadataConfig->options->toArray();
    if (isset($optionsArr['adapter'])) {
        if (array_key_exists($optionsArr['adapter'], $backendConfig->toArray())) {
            $backendOption = clone $backendConfig->{$optionsArr['adapter']};
            $optionsArr = $backendOption->merge(new Config($optionsArr))->toArray();
        }
    } else {
        throw new \Exception('modelsMetadata必须设置adapter');
    }
    if ($optionsArr['adapter'] == 'files') {
        if (empty($optionsArr['meta_data_dir'])) {
            throw new \Exception('缓存目录不能为空');
        }
        $dir = Common::dirFormat($optionsArr['meta_data_dir']);
        $mkdirRes = Common::mkdir($dir);
        if (!$mkdirRes) {
            throw new \Exception('创建目录 ' . $dir . ' 失败');
        }
    }
    $optionsArr = Common::convertArrKeyUnderline($optionsArr);
    $modelsMetadataClassName = 'Phalcon\\Mvc\\Model\\MetaData\\' . Text::camelize($optionsArr['adapter']);
    $modelsMetadata = new $modelsMetadataClassName($optionsArr);
    return $modelsMetadata;
});

完整的config/services.php

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

use Common\Common;
use Common\Validate;
use Library\Extensions\VoltExtension;
use Library\Plugins\DbProfilerPlugin;
use Library\Plugins\DIspatcherPlugin;
use Phalcon\Cache\Frontend\Factory as CacheFrontendFactory;
use Phalcon\Cache\Backend\Factory as CacheBackendFactory;
use Phalcon\Config;
use Phalcon\Crypt;
use Phalcon\Db\Adapter\Pdo\Mysql;
use Phalcon\Db\Profiler;
use Phalcon\DI;
use Phalcon\Di\FactoryDefault;
use Phalcon\Events\Manager as EventsManager;
use Phalcon\Http\Response\Cookies;
use Phalcon\Logger\Adapter\File as LoggerAdapterFile;
use Phalcon\Logger\Formatter\Line as LoggerFormatterLine;
use Phalcon\Mvc\Dispatcher;
use Phalcon\Mvc\Router;
use Phalcon\Mvc\View;
use Phalcon\Mvc\View\Engine\Volt as ViewEngineVolt;
use Phalcon\Mvc\View\Engine\Php as ViewEnginePhp;
use Phalcon\Session\Factory as SessionFactory;
use Phalcon\Text;

$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);
    $eventsManager = new EventsManager();
    $eventsManager->attach('dispatch', new DIspatcherPlugin());
    $dispatcher->setEventsManager($eventsManager);
    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 注册视图引擎volt服务
 * @author zhaoyang
 * @date 2018年5月4日 下午5:28:52
 */
$di->setShared('viewEngineVolt', function (View $view, DI $di) {
    // 获取config服务有多种方法,这是其一
    $voltConfig = $di->get('config')->services->view_engine_volt->toArray();
    $voltConfig = Common::convertArrKeyUnderline($voltConfig);
    $viewEngineVolt = new ViewEngineVolt($view, $di);
    $voltConfig['compiledPath'] = isset($voltConfig['compiledPath']) ? Common::dirFormat($voltConfig['compiledPath']) : BASE_PATH . 'runtime/' . DEFAULT_MODULE . '/compiled/volt' . DS;
    $mkdirRes = Common::mkdir($voltConfig['compiledPath']);
    if (!$mkdirRes) {
        throw new \Exception('创建目录 ' . $voltConfig['compiledPath'] . ' 失败');
    }
    $viewEngineVolt->setOptions($voltConfig);
    // 获取编译器对象
    $compiler = $viewEngineVolt->getCompiler();
    // 添加扩展
    $compiler->addExtension(new VoltExtension());
    return $viewEngineVolt;
});

/**
 * @desc 注册视图引擎php服务
 * @author zhaoyang
 * @date 2018年5月4日 下午5:29:15
 */
$di->setShared('viewEnginePhp', function (View $view, DI $di) {
    $viewEnginePhp = new ViewEnginePhp($view, $di);
    return $viewEnginePhp;
});

/**
 * @desc 注册视图服务
 * @author zhaoyang
 * @date 2018年5月3日 下午10:52:37
 */
$di->set('view', function () {
    // 获取config服务有多种方法,这是其二
    $viewConfig = $this->getConfig()->services->view;
    $viewDir = $viewConfig->view_path ?? APP_PATH . DEFAULT_MODULE . '/views' . DS;
    if (isset($viewConfig->view_suffix)) {
        $viewSuffixs = explode(',', $viewConfig->view_suffix);
    } else {
        $viewSuffixs = [ 
            'volt'
        ];
    }
    if (isset($viewConfig->view_service)) {
        $viewServices = explode(',', $viewConfig->view_service);
    } else {
        $viewServices = [ 
            'viewEngineVolt'
        ];
    }
    $engines = [ ];
    foreach ($viewSuffixs as $k => $v) {
        $suffix = '.' . ltrim($v, '.');
        $engines[$suffix] = $viewServices[$k] ?? $viewServices[0];
    }
    $view = new View();
    // 设置视图路径
    $view->setViewsDir($viewDir);
    // 注册视图引擎
    $view->registerEngines($engines);
    // 如果不需要“生成显示到控制器布局”和“生成显示到主布局”,则关闭这两个渲染级别
    $view->disableLevel([ 
        View::LEVEL_LAYOUT => true,
        View::LEVEL_MAIN_LAYOUT => true
    ]);
    return $view;
});

/** 
 * @desc 注册验证服务 
 * @author zhaoyang 
 * @date 2018年5月11日 下午7:26:30 
 */
$di->set('validate', function () {
    $validate = new Validate();
    return $validate;
});

/** 
 * @desc 注册性能分析组件 
 * @author zhaoyang 
 * @date 2018年5月20日 下午9:34:33 
 */
$di->setShared('profiler', function () {
    $profiler = new Profiler();
    return $profiler;
});

/** 
 * @desc 注册数据库(连接)服务 
 * @author zhaoyang 
 * @date 2018年5月14日 下午9:01:36 
 */
$di->setShared('db', function () {
    $dbConfig = $this->getConfig()->services->db->toArray();
    $mysql = new Mysql($dbConfig);
    if ($dbConfig['logged'] ?? false) {
        $eventsManager = new EventsManager();
        $eventsManager->attach('db', new DbProfilerPlugin());
        $mysql->setEventsManager($eventsManager);
    }
    return $mysql;
});

/** 
 * @desc 注册日志服务 
 * @author zhaoyang 
 * @date 2018年5月19日 下午6:20:36 
 */
$di->set('logger', function (string $file = null, array $line = null) {
    $config = $this->getConfig()->services->logger;
    $linConfig = clone $config->line;
    if (!is_null($line)) {
        $linConfig = $linConfig->merge(new Config($line));
    }
    $loggerFormatterLine = new LoggerFormatterLine($linConfig->format, $linConfig->date_format);
    $fileConfig = $config->file;
    if (empty($file)) {
        $file = $fileConfig->info;
    } else if (array_key_exists($file, $fileConfig->toArray())) {
        $file = $fileConfig->$file;
    }
    $file = Common::dirFormat($file);
    $dir = dirname($file);
    $mkdirRes = Common::mkdir($dir);
    if (!$mkdirRes) {
        throw new \Exception('创建目录 ' . $dir . ' 失败');
    }
    $loggerAdapterFile = new LoggerAdapterFile($file);
    $loggerAdapterFile->setFormatter($loggerFormatterLine);
    return $loggerAdapterFile;
});

/** 
 * @desc 注册session服务 
 * @author zhaoyang 
 * @date 2018年5月26日 下午4:48:03 
 */
$di->setShared('session', function () {
    $sessionConfig = $this->getConfig()->services->session;
    $backendConfig = $this->getConfig()->services->cache->backend;
    $optionsArr = $sessionConfig->options->toArray();
    if (isset($optionsArr['adapter'])) {
        if (array_key_exists($optionsArr['adapter'], $backendConfig->toArray())) {
            $backendOption = clone $backendConfig->{$optionsArr['adapter']};
            $optionsArr = $backendOption->merge(new Config($optionsArr))->toArray();
        }
    } else {
        throw new \Exception('session必须设置adapter');
    }
    $optionsArr = Common::convertArrKeyUnderline($optionsArr);
    if (version_compare(PHALCON_VERSION, '3.2.0', '>')) {
        $session = SessionFactory::load($optionsArr);
    } else {
        $adapterClassName = 'Phalcon\\Session\\Adapter\\' . Text::camelize($optionsArr['adapter']);
        $session = new $adapterClassName($optionsArr);
    }
    if ($sessionConfig->auto_start) {
        $session->start();
    }
    return $session;
});

/** 
 * @desc 注册加密服务 
 * @author zhaoyang 
 * @date 2018年5月28日 下午8:17:46 
 */
$di->set('crypt', function (string $key = null, int $padding = null, string $cipher = null) {
    $cryptConfig = $this->getConfig()->services->crypt;
    $crypt = new Crypt();
    if (!empty($cryptConfig->key) || !empty($padding)) {
        $crypt->setKey($key ?? $cryptConfig->key);
    }
    if (!empty($cryptConfig->padding) || !empty($key)) {
        $crypt->setPadding($padding ?? $cryptConfig->padding);
    }
    if (!empty($cryptConfig->cipher) || !empty($cipher)) {
        $crypt->setCipher($cipher ?? $cryptConfig->cipher);
    }
    return $crypt;
});

/** 
 * @desc 注册cookies服务 
 * @author zhaoyang 
 * @date 2018年5月29日 上午9:54:23 
 */
$di->set('cookies', function () {
    $cookiesConfig = $this->getConfig()->services->cookies;
    $cookies = new Cookies();
    if (isset($cookiesConfig->use_encryption)) {
        $cookies->useEncryption((bool) $cookiesConfig->use_encryption);
    }
    return $cookies;
});

/** 
 * @desc 注册缓存 
 * @author zhaoyang 
 * @date 2018年5月30日 下午10:30:29 
 */
$di->set('cache', function (array $options = []) {
    $cacheConfig = $this->getConfig()->services->cache;
    $frontendConfig = $cacheConfig->frontend;
    if (isset($options['frontend']['adapter'])) {
        $frontendOption = new Config($options['frontend']);
        if (array_key_exists($options['frontend']['adapter'], $frontendConfig->toArray())) {
            $frontendOptionClone = clone $frontendConfig->{$options['frontend']['adapter']};
            $frontendOptionClone->merge($frontendOption);
            $frontendOption = $frontendOptionClone;
        }
    } else {
        $frontendOption = clone $frontendConfig->data;
        $frontendOption->adapter = 'data';
    }
    $frontendOption = Common::convertArrKeyUnderline($frontendOption->toArray());
    if (version_compare(PHALCON_VERSION, '3.2.0', '>')) {
        $frontendCache = CacheFrontendFactory::load($frontendOption);
    } else {
        $frontendClassName = 'Phalcon\\Cache\\Frontend\\' . Text::camelize($frontendOption['adapter']);
        $frontendCache = new $frontendClassName($frontendOption);
    }
    $backendConfig = $cacheConfig->backend;
    if (isset($options['backend']['adapter'])) {
        $backendOption = new Config($options['backend']);
        if (array_key_exists($options['backend']['adapter'], $backendConfig->toArray())) {
            $backendOptionClone = clone $backendConfig->{$options['backend']['adapter']};
            $backendOptionClone->merge($backendOption);
            $backendOption = $backendOptionClone;
        }
    } else {
        $backendOption = clone $backendConfig->file;
        $backendOption->adapter = 'file';
    }
    if ($backendOption->adapter == 'file') {
        if (empty($dir = $backendOption->cache_dir)) {
            throw new \Exception('缓存目录不能为空');
        }
        $dir = Common::dirFormat($dir);
        $mkdirRes = Common::mkdir($dir);
        if (!$mkdirRes) {
            throw new \Exception('创建目录 ' . $dir . ' 失败');
        }
    }
    $backendOption = Common::convertArrKeyUnderline($backendOption->toArray());
    if (version_compare(PHALCON_VERSION, '3.2.0', '>')) {
        $backendOption['frontend'] = $frontendCache;
        $backendCache = CacheBackendFactory::load($backendOption);
    } else {
        $backendClassName = 'Phalcon\\Cache\\Backend\\' . Text::camelize($backendOption['adapter']);
        $backendCache = new $backendClassName($frontendCache, $backendOption);
    }
    return $backendCache;
});

/** 
 * @desc 注册 modelsMetadata服务
 * @author zhaoyang 
 * @date 2018年6月2日 下午10:39:43 
 */
$di->setShared('modelsMetadata', function () {
    $modelsMetadataConfig = $this->getConfig()->services->models_metadata;
    $backendConfig = $this->getConfig()->services->cache->backend;
    $optionsArr = $modelsMetadataConfig->options->toArray();
    if (isset($optionsArr['adapter'])) {
        if (array_key_exists($optionsArr['adapter'], $backendConfig->toArray())) {
            $backendOption = clone $backendConfig->{$optionsArr['adapter']};
            $optionsArr = $backendOption->merge(new Config($optionsArr))->toArray();
        }
    } else {
        throw new \Exception('modelsMetadata必须设置adapter');
    }
    if ($optionsArr['adapter'] == 'files') {
        if (empty($optionsArr['meta_data_dir'])) {
            throw new \Exception('缓存目录不能为空');
        }
        $dir = Common::dirFormat($optionsArr['meta_data_dir']);
        $mkdirRes = Common::mkdir($dir);
        if (!$mkdirRes) {
            throw new \Exception('创建目录 ' . $dir . ' 失败');
        }
    }
    $optionsArr = Common::convertArrKeyUnderline($optionsArr);
    $modelsMetadataClassName = 'Phalcon\\Mvc\\Model\\MetaData\\' . Text::camelize($optionsArr['adapter']);
    $modelsMetadata = new $modelsMetadataClassName($optionsArr);
    return $modelsMetadata;
});

4、在home模块下新增Robots.php模型(前面在Phalcon搭建多模块框架十:注册数据库服务及模型简单增删改查写过,不在重复写)
5、在home模块下新增RobotsController.php控制器(前面在Phalcon搭建多模块框架十:注册数据库服务及模型简单增删改查写过,不在重复写)
6、访问/robots/index
浏览器可以看到
这里写图片描述
打开runtime目录可以看到如下
这里写图片描述
其中models_metadata下的就是Robots.php模型对应的表结构数据,mysql下的就是sql语句记录。
先看mysql的log日志

[2018-06-02 22:51:29][INFO] SELECT IF(COUNT(*) > 0, 1, 0) FROM `INFORMATION_SCHEMA`.`TABLES` WHERE `TABLE_NAME` = 'ph_robots' AND `TABLE_SCHEMA` = DATABASE() null 0.0013370513916016
[2018-06-02 22:51:29][INFO] DESCRIBE `ph_robots` null 0.0024740695953369
[2018-06-02 22:51:29][INFO] SELECT `ph_robots`.`id`, `ph_robots`.`name`, `ph_robots`.`type`, `ph_robots`.`weight` FROM `ph_robots` null 0.00075984001159668

再看map-app_home_models_robots.php

<?php return array (
  0 => NULL,
  1 => NULL,
); 

打开meta-app_home_models_robots-ph_robots.php可以看到

<?php return array (
  0 => 
  array (
    0 => 'id',
    1 => 'name',
    2 => 'type',
    3 => 'weight',
  ),
  1 => 
  array (
    0 => 'id',
  ),
  2 => 
  array (
    0 => 'name',
    1 => 'type',
    2 => 'weight',
  ),
  3 => 
  array (
    0 => 'id',
    1 => 'name',
    2 => 'type',
    3 => 'weight',
  ),
  4 => 
  array (
    'id' => 0,
    'name' => 2,
    'type' => 0,
    'weight' => 0,
  ),
  5 => 
  array (
    'id' => true,
    'type' => true,
    'weight' => true,
  ),
  8 => 'id',
  9 => 
  array (
    'id' => 1,
    'name' => 2,
    'type' => 1,
    'weight' => 1,
  ),
  10 => 
  array (
  ),
  11 => 
  array (
  ),
  12 => 
  array (
  ),
  13 => 
  array (
  ),
); 

7、将mysql目录删除,再次访问/robots/index
可以看到runtime下再次生成mysql目录,打开mysql下的日志文件可以看到只有一条查询语句。因为表结构直接读取models_metadata目录下的两文件了。

[2018-06-02 23:06:41][INFO] SELECT `ph_robots`.`id`, `ph_robots`.`name`, `ph_robots`.`type`, `ph_robots`.`weight` FROM `ph_robots` null 0.0020918846130371

当删除models_metadata目录时,再次访问/robots/index,则又是三条语句。
注:不推荐使用files,因为没有过期时间,表结构变动后很麻烦。这次使用files纯粹为了展示效果

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值