基本使用phalcon

安装

wget https://github.com/phalcon/cphalcon/archive/v3.4.1.tar.gz
cd cphalcon/build/
./install --phpize /mnt/d/vhs/php/php71phlone/bin/phpize --php-config /mnt/d/vhs/php/php71phlone/bin/php-config
# OR
cd /cphalcon/build/php7/64bits
phpize
./configure
make
sudo make install
echo "extension=phalcon.so" > /etc/opt/appnode/scls/appnode-php71/php.d/99-Phalcon.ini

idea 提示

composer require phalcon/ide-stubs

通过 phalcon-devtools 创建项目基本结构

# 创建多多模块的项目
# /opt/appnode/appnode-php71/root/bin/php /home/vagrant/phalcon-devtools-3.4.0/phalcon.php create-project projectName --type=modules
phalcon project projectName --type=modules

# 基本使用
/opt/appnode/appnode-php71/root/bin/php /home/vagrant/phalcon-devtools-3.4.0/phalcon.php
# 创建模型
/opt/appnode/appnode-php71/root/bin/php /home/vagrant/phalcon-devtools-3.4.0/phalcon.php model --name order --namespace=Demo\\Modules\\Frontend\\Models --output=/vagrant_data/test_lxx_mo/app/modules/frontend/models

## 如果提示未找到配置文件,查看是不是rootPath有误,在__construct()里面重新指定根目录即可
/home/vagrant/phalcon-devtools-3.4.0/scripts/Phalcon/Builder/Path.php
$this->rootPath = '/vagrant_data/test_lxx_mo/';

跨模块使用,需要注册对应模块的命名空间

# 如在 CLI(bootstrap_cli)模块使用Frontend模块,那么应该在CLI模块里面的loader注册Frontend的命名空间
$loader->registerNamespaces([
    'Demo\Common\Models' => APP_PATH . '/common/models/',
    'Demo\Common\Library' => APP_PATH . '/common/library/',
    'Demo\Modules\Frontend' => APP_PATH . '/modules/frontend/', // 注册Frontend模块,在APP_PATH . '/modules/frontend/'目录里面存在这个文件app/modules/frontend/Module.php
]);

使用多模块mvc

创建多模块目录和控制器 模块wap 创建一个默认的控制器 /app/wap/controllers/IndexController.php

<?php

namespace App\Wap\Controllers;

use Phalcon\Mvc\Controller;

class IndexController extends Controller
{
    public function indexAction()
    {
        $this->view->pick("index/index");
    }
    public function loginAction()
    {
        $this->view->pick("index/login");
    }
}

每一个模块都存在一个Module配置,必需包含registerAutoloaders和registerServices 独立出来的配置 /app/wap/Module.php

<?php

namespace App\Wap;

use Phalcon\Loader;
use Phalcon\Mvc\View;
use Phalcon\DiInterface;
use Phalcon\Mvc\Dispatcher;
use Phalcon\Mvc\ModuleDefinitionInterface;

class Module implements ModuleDefinitionInterface
{
    /**
     * 注册自定义加载器
     */
    public function registerAutoloaders(DiInterface $di = null)
    {
        $loader = new Loader();

        $loader->registerNamespaces(
            [
                'App\Wap\Controllers' => APP_PATH . '/wap/controllers/'
            ]
        );

        $loader->register();
    }

    /**
     * 注册自定义服务
     */
    public function registerServices(DiInterface $di)
    {
        // Registering a dispatcher
        $di->set(
            "dispatcher",
            function () {
                $dispatcher = new Dispatcher();

                $dispatcher->setDefaultNamespace('App\\Wap\\Controllers');

                return $dispatcher;
            }
        );

        // Registering the view component
        $di->set(
            "view",
            function () {
                $view = new View();
                $view->setViewsDir("../app/views/wap/");
                return $view;
            }
        );
    }
}

配置路由 /app/config/router.php

<?php

$router = $di->getRouter();

// Define your routes here
$router->add(
    "/wap",
    [
        "module"     => "wap",
        "controller" => 'index',
        "action"     => 'index',
    ]
);
$router->add(
    "/wap/index",
    [
        "module"     => "wap",
        "controller" => 'index',
        "action"     => 'index',
    ]
);
$router->add(
    "/wap/:controller/:action",
    [
        "module"     => "wap",
        "controller" => 1,// :controller 参数
        "action"     => 2,// :action 参数
    ]
);

$router->handle();

配置入口文件 注册多模块 /public/index.php

$application = new \Phalcon\Mvc\Application($di);
    /**
     * 注册多模块
     */
    $application->registerModules([
        'wap' => [
            'className' => 'App\Wap\Module',
            'path'      => APP_PATH . '/wap/Module.php',
        ]
    ]);

创建模板文件 /app/views/wap/index/index.phtml 访问即可 http://host/wap/index/index http://host/wap/index/login

这是html

隐藏index.php webserver-setup#nginx

nginx原文

server {
    listen       80;
    server_name  192.168.1.114;
    root         /var/www/phalcon/public/;
    index        index.html index.htm index.php;

    location / {
        try_files  $uri $uri/ /index.php?_url=$uri&$args;
    }

    location ~ ^/.+\.php {
        fastcgi_index            index.php;
        fastcgi_split_path_info  ^(.+\.php)(/.*)$;
        fastcgi_param            SCRIPT_FILENAME $request_filename;
        fastcgi_param            PATH_INFO $fastcgi_path_info;
        fastcgi_param            PATH_TRANSLATED $document_root$fastcgi_path_info;
        include                  fastcgi_params;
        fastcgi_pass             127.0.0.1:9000;
    #fastcgi_pass  unix:/var/run/php-fpm/php-fpm.sock;
    }

    location ~ /\.ht {
        deny  all;
    }
}

lighttpd原文

#######################################################################
##
## For more examples check:
##
## https://redmine.lighttpd.net/projects/lighttpd/wiki/Docs_Configuration
##
$HTTP["host"] == "lxx.phalcon.net" {
  var.server_name = "lxx.phalcon.net"

  url.rewrite-if-not-file = (
      "^/(.+)/?$" => "/index.php/?_url=/$1",
  )
  server.name = server_name
  ## example how to include another config:
  ## use trigger before download
  ## 
  # include "conf.d/trigger_b4_dl.conf"

  server.document-root = "/home/lxx/work/tp/phalcon-demo/public/"
  ##
  ## use a seperate access log file
  ## At the moment you cant have different error log files.
  ##
  #accesslog.filename          = log_root + "/" + server_name + "/access.log"
}



##
#######################################################################

php 内置服务器

php -S localhost:8000 -t /public .htrouter.php

# .htrouter.php
<?php
if (!file_exists(__DIR__ . '/' . $_SERVER['REQUEST_URI'])) {
    $_GET['_url'] = $_SERVER['REQUEST_URI'];
}
return false;

index.php原文

<?php

use Phalcon\Di\FactoryDefault;

error_reporting(E_ALL);

define('BASE_PATH', dirname(__DIR__));
define('APP_PATH', BASE_PATH . '/app');

try {
    
    /**
     * The FactoryDefault Dependency Injector automatically registers
     * the services that provide a full stack framework.
     */
    $di = new FactoryDefault();
    
    /**
     * Handle routes
     */
    include APP_PATH . '/config/router.php';
    
    /**
     * Read services
     */
    include APP_PATH . '/config/services.php';
    
    /**
     * Get config service for use in inline setup below
     */
    $config = $di->getConfig();
    
    /**
     * Include Autoloader
     */
    include APP_PATH . '/config/loader.php';
    
    /**
     * Include Composer Autoloader
     */
    include BASE_PATH . '/vendor/autoload.php';
    
    /**
     * Handle the request
     */
    $application = new \Phalcon\Mvc\Application($di);
    /**
     * 注册多模块
     */
    $application->registerModules([
        'wap' => [
            'className' => 'App\Wap\Module',
            'path'      => APP_PATH . '/wap/Module.php',
        ]
    ]);
    echo str_replace(["\n", "\r", "\t"], '', $application->handle()->getContent());
    
} catch (\Exception $e) {
    echo $e->getMessage() . '<br>';
    echo '<pre>' . $e->getTraceAsString() . '</pre>';
}

控制器和模型的命名空间

配置命名空间 文件:phalcon/app/config/loader.php

<?php

$loader = new \Phalcon\Loader();

/**
 * We're a registering a set of directories taken from the configuration file
 */

$loader->registerDirs([$config->application->controllersDir, $config->application->modelsDir]);
// 加载一下命名空间
$loader->registerNamespaces([
    'App\\Models'      => APP_PATH . '/models/',
    'App\\Library'     => APP_PATH . '/library/',
    'App\\Controllers' => APP_PATH . '/controllers/']);
$loader->register();

Registering a dispatcher 文件:phalcon/app/config/services.php

use Phalcon\Mvc\Dispatcher;
// Registering a dispatcher
// 默认命名空间
$di->set(
    "dispatcher",
    function () {
        $dispatcher = new Dispatcher();

        $dispatcher->setDefaultNamespace(
            "App\\Controllers"
        );

        return $dispatcher;
    }
);

注册模版引擎服务/Volt模版引擎

文件:phalcon/app/config/services.php

use Phalcon\Mvc\View\Engine\Volt as VoltEngine;
use Phalcon\Mvc\View;
// 注册模版引擎服务
$di->set(
    "voltService",
    function ($view, $di) {
        $volt = new VoltEngine($view, $di);

        $volt->setOptions(
            [
                "compiledPath" => "../app/views/",
                // "compiledExtension" => ".compiled",
            ]
        );

        return $volt;
    }
);
// Register Volt as template engine
// 注册Volt模版引擎
$di->set(
    "view",
    function () {
        $view = new View();

        $view->setViewsDir("../app/views/");

        $view->registerEngines(
            [
                ".volt"  => "voltService",
                ".phtml" => "voltService",
            ]
        );

        return $view;
    }
);

关于生成的路径带index.php

修改配置baseUri 文件:phalcon/app/config/config.php

'baseUri'        => '',

配置原文/数据库配置

<?php
/*
 * Modified: prepend directory path of current file, because of this file own different ENV under between Apache and command line.
 * NOTE: please remove this comment.
 */
defined('BASE_PATH') || define('BASE_PATH', getenv('BASE_PATH') ?: realpath(dirname(__FILE__) . '/../..'));
defined('APP_PATH') || define('APP_PATH', BASE_PATH . '/app');
return new \Phalcon\Config([
    'database' => [
        'adapter'     => 'Mysql',
        'host'        => '127.0.0.1:3306',
        'username'    => 'root',
        'password'    => '19961129',
        'dbname'      => 'phalcon',
        'charset'     => 'utf8',
    ],
    'application' => [
        'appDir'         => APP_PATH . '/',
        'controllersDir' => APP_PATH . '/controllers/',
        'modelsDir'      => APP_PATH . '/models/',
        'migrationsDir'  => APP_PATH . '/migrations/',
        'viewsDir'       => APP_PATH . '/views/',
        'pluginsDir'     => APP_PATH . '/plugins/',
        'libraryDir'     => APP_PATH . '/library/',
        'cacheDir'       => BASE_PATH . '/cache/',

        // This allows the baseUri to be understand project paths that are not in the root directory
        // of the webpspace.  This will break if the public/index.php entry point is moved or
        // possibly if the web server rewrite rules are changed. This can also be set to a static path.
         'baseUri'        => '',
        // 'baseUri'        => preg_replace('/public([\/\\\\])index.php$/', '', $_SERVER["PHP_SELF"]),
    ]
]);

Composer使用

加载Composer 文件:phalcon/public/index.php

    /**
     * Include Composer Autoloader
     */
    include BASE_PATH . '/vendor/autoload.php';

入口文件原文

<?php
use Phalcon\Di\FactoryDefault;

error_reporting(E_ALL);

define('BASE_PATH', dirname(__DIR__));
define('APP_PATH', BASE_PATH . '/app');

try {

    /**
     * The FactoryDefault Dependency Injector automatically registers
     * the services that provide a full stack framework.
     */
    $di = new FactoryDefault();

    /**
     * Handle routes
     */
    include APP_PATH . '/config/router.php';

    /**
     * Read services
     */
    include APP_PATH . '/config/services.php';

    /**
     * Get config service for use in inline setup below
     */
    $config = $di->getConfig();

    /**
     * Include Autoloader
     */
    include APP_PATH . '/config/loader.php';

    /**
     * Include Composer Autoloader
     */
    include BASE_PATH . '/vendor/autoload.php';

    /**
     * Handle the request
     */
    $application = new \Phalcon\Mvc\Application($di);

    echo str_replace(["\n", "\r", "\t"], '', $application->handle()->getContent());

} catch (\Exception $e) {
    echo $e->getMessage() . '<br>';
    echo '<pre>' . $e->getTraceAsString() . '</pre>';
}

获取值

(1)直接获取值:
 $customerName = $this->request->getPost("name");
(2)自动添加过滤器:
 $email = $this->request->getPost("user_email", "email");
(3)手动添加过滤器:
 $filter = new Filter();
 $email  = $filter->sanitize($this->request->getPost("user_email"), "email");
(4)若值为空,设置默认值
 $email = $this->request->getPost("user_email", "email", "[email protected]");
(5)获取ajax的json
 $robot = $app->request->getJsonRawBody();
 $robot->name;

过滤数据

use Phalcon\Filter;

$filter = new Filter();
// 返回 "Hello"
$filter->sanitize("<h1>Hello</h1>", "striptags");
// 返回 "Hello"
$filter->sanitize("  Hello   ", "trim");
// 返回 "Hello"
$filter->sanitize(
    "   <h1> Hello </h1>   ",
    [
        "striptags",
        "trim",
    ]
);

返回json

$this->response->setJsonContent([
          "status"   => "ERROR",
          "messages" => $errors,
          ]);
        return $this->response;

响应/请求

// 检查请求是否为POST
        if ($this->request->isPost()) {
            // 获取POST数据
            $customerName = $this->request->getPost("name");
            $customerBorn = $this->request->getPost("born");
        }

模型

读取

# 读取
$user = new UsersModel();
$find = UsersModel::findFirst(3);

$users = UsersModel::find(
    [
        "mobile = :mobile: AND password = :password:",
        "bind" => [
            "mobile"   => $data['user'],
            "password" => md5($data['password']),
        ],
    ]
);
$users->count();
# 结果集的第一条
$loginuser = $users->getFirst();
$loginuser->id;
# 单条
$users = new UsersModel();
$loginuser = $users->findFirst(1);
# 
UsersModel::findFirstById(3);
# 全部
$smsloglist = $smslog->find();

参数绑定 查询选项

$articleModel->find([
  'columns' => 'aid, title', //查询字段
  'conditions' => 'aid = :aid:',  //查询条件
  'bind' => [ //参数绑定
    'aid' => 2
  ],
  'order' => 'aid DESC', //排序
  'limit' => 10, //限制查询结果的数量
  'offset' => 10, //偏移量
 ]);
# in的用法
 $result3 = $articleModel->find([
  'conditions' => 'aid IN ({aids:array})',
    'bind' => [
      'aids' => [1, 2]
    ],
]);
# like的用法
$result4 = $articleModel->find([
  'conditions' => 'title like :title:',
  'bind' => [
    'title' => '%英语%',
  ],
]);

添加单条记录

$articleModel = new ArticlesModel();
$result = $articleModel->create([
    'title' => 'phalcon测试',
    'introduce' => 'Phalcon入门教程',
    'status' => 1,
    'view_number' => 1,
    'is_recommend' => 1,
    'is_top' => 1,
    'create_by' => 1,
    'create_time' => date('Y-m-d H:i:s'),
    'modify_by' => 1,
    'modify_time' => date('Y-m-d H:i:s')
]);
# 更新
# 默认判断数据的非空,在模型初始化initialize里面
$this->setup(
    array('notNullValidations' => false)
);
# 先调用 findFirst() 获取一条记录,返回值是当前模型对象 // 
# 使用返回的模型对象调用 update() 函数执行更新操作
$articleModel = new ArticlesModel();
$article = $articleModel->findFirst([
    'conditions' => 'aid = :aid:',
    'bind' => [
        'aid' => 3
    ],
]);
# $users = new UsersModel();
# $loginuser = $users->findFirst(1);
if($article) {
    //使用返回的模型对象调用 update() 函数执行更新操作
    $result = $article->update([
        'title' => 'Phalcon更新测试1',
    ]);
    //update() 函数返回值为boolean
    var_dump($result);
}

注入think orm

/**
 * 使用think orm
 * composer require topthink/think-orm
 */
$di->setShared('thinkorm', function () {
    $config     = $this->getConfig();
    $params     = [
        'type'     => $config->database->adapter,
        'hostname' => $config->database->host,
        'username' => $config->database->username,
        'password' => $config->database->password,
        'database' => $config->database->dbname,
        'charset'  => $config->database->charset,
    ];
    $class      = 'think\Db';
    $connection = new $class($params);
    $connection->setConfig($params);
    return $connection;
});

使用

function indexAction()
    {
        $Db  = $this->thinkorm;
        $ret = $Db::table('phalcon_sms_log')->find();
    // $ret = ($this->thinkorm)::table('phalcon_sms_log')->find();
        var_dump($ret);
        die();
    }

注入

使用nette/database

/**
 * 使用nette/database
 * Building queries, advanced joins, drivers for MySQL, PostgreSQL, SQLite, MS SQL Server and Oracle.
 * https://doc.nette.org/en/2.4/database-core
 * composer require nette/database
 */
$di->setShared('pdodatabase', function () {
    $config     = $this->getConfig();
    $params     = [
        'type'     => $config->database->adapter,
        'hostname' => $config->database->host,
        'username' => $config->database->username,
        'password' => $config->database->password,
        'database' => $config->database->dbname,
        'charset'  => $config->database->charset,
    ];
    $class      = 'Nette\Database\Connection';
    $connection = new $class(strtolower($params['type']) . ':' . 'host=' . $params['hostname'] . ';dbname=' . $params['database'], $params['username'], $params['password']);
    return $connection;
});

使用

public function indexAction()
    {
  // 打印sql和信息
        $ret = $this->pdodatabase->query('SELECT * FROM phalcon_sms_log')->dump();
        die();
    }

cookie

$this->cookies->set(
    "uid",
    $loginuser->id,
    time() + 60 * 60 * 24 * 15
);
# 删除
$cookieuid = $this->cookies->get("uid");
$cookieuid->delete();

模板渲染

赋值

// 赋值
$this->view->password = '';
// 选择视图
 $this->view->pick("index/login");

Volt模板渲染

用户姓名:{{userinfo.id}}
{% for vo in smsloglist %}
    <div>
      ID: {{ vo.id|e }}
      {% if vo.is_send == "1" %}
        发送ok
      {% endif  %}
    </div>
{% endfor  %}

加载公共部分

<?php $this->partial("public/assets_head"); ?>

原文

<html>

<head>
    <title>用户主页</title>
    <?php $this->partial("public/assets_head"); ?>
    <style type="text/css">
    .weui_cells {
        margin-bottom: 1.17647059em;
    }
    </style>
</head>
<body ontouchstart="" style="background-color: #f8f8f8;">

</body>

</html>

资源文件

例子

<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1,user-scalable=0">
<link rel="stylesheet" href="/css/weui/style/weui.css">
<link rel="stylesheet" href="/css/weui/style/weui2.css">
<link rel="stylesheet" href="/css/weui/style/weui3.css">
<script src="/css/weui/zepto.min.js"></script>

实际目录 相对于/public/目录

/public/css/weui/zepto.min.js

分页

use App\Models\SmsLogs as SmsLogsModel; // 表
use Phalcon\Paginator\Adapter\Model as PaginatorModel; // 分页
// $this->request->getQuery("page", "int"); // GET
// $this->request->getPost("page", "int"); // POST
$currentPage = $this->request->getQuery("page", "int");
$smslog = SmsLogsModel::find();
$paginator = new PaginatorModel([
    "data"  => $smslog,
    "limit" => 2,
    "page"  => $currentPage,
]);
$page = $paginator->getPaginate();
$this->view->page = $page; // 渲染到数据
// 前端
<body ontouchstart="" style="background-color: #f8f8f8;">
    <table>
        <?php foreach ($page->items as $item) { ?>
            <tr>
                <td><?php echo $item->id; ?></td>
            </tr>
        <?php } ?>
    </table>
    <div>
      <a href="/user/index">首页</a>
      <a href="/user/index?page=<?= $page->before; ?>">上一页</a>
      <a href="/user/index?page=<?= $page->next; ?>">下一页</a>
      <a href="/user/index?page=<?= $page->last; ?>">末页</a>
      <?php echo "当前页", $page->current, " 共 ", $page->total_pages,"条:", $page->total_items; ?>
    </div>
</body>

获取di

$this->getDI()->get('config');

命令行使用

# 创建admin模块
/opt/appnode/appnode-php71/root/bin/php /home/vagrant/phalcon-devtools-3.4.0/phalcon.php module --name admin --namespace=Demo\\Modules --output=/vagrant_data/test_lxx_mo/app/modules

# 创建公共模型
/opt/appnode/appnode-php71/root/bin/php /home/vagrant/phalcon-devtools-3.4.0/phalcon.php model --name order --namespace=Demo\\Common\\Models --output=/vagrant_data/test_lxx_mo/app/common/models

# 创建admin基类控制器
/opt/appnode/appnode-php71/root/bin/php /home/vagrant/phalcon-devtools-3.4.0/phalcon.php controller --name base --namespace=Demo\\Modules\\Admin\\Controllers --output=/vagrant_data/test_lxx_mo/app/modules/admin/controllers
# 创建admin的index控制器
/opt/appnode/appnode-php71/root/bin/php /home/vagrant/phalcon-devtools-3.4.0/phalcon.php controller --name index --namespace=Demo\\Modules\\Admin\\Controllers --base-class=\\Demo\\Modules\\Admin\\Controllers\\BaseController --output=/vagrant_data/test_lxx_mo/app/modules/admin/controllers
# app/bootstrap_web.php文件注册模块(web服务里面引入多模块)
/**
* 注册模块,$application->getModules();可以获取当前所有模块(路由可使用)
*/
$application->registerModules([
    'frontend' => ['className' => 'Demo\Modules\Frontend\Module'],
    'admin' => ['className' => 'Demo\Modules\Admin\Module'],
]);


# $loader里面注册Admin模块

/**
 * 首先注册命名空间进行加载
 */
$loader->registerNamespaces([
    // 公共部分
    'Demo\Common\Models' => APP_PATH . '/common/models/',
    'Demo\Common\Library' => APP_PATH . '/common/library/',
    // 不同模块部分
    'Demo\Modules\Frontend' => APP_PATH . '/modules/frontend/',
    'Demo\Modules\Admin' => APP_PATH . '/modules/admin/',
]);

/**
 * 注册新的模块的类文件(该Module.php文件又会注册命名空间,包含该模块的控制器等)
 */
$loader->registerClasses([
    'Demo\Modules\Frontend\Module' => APP_PATH . '/modules/frontend/Module.php',
    'Demo\Modules\Admin\Module' => APP_PATH . '/modules/admin/Module.php',
    'Demo\Modules\Cli\Module'      => APP_PATH . '/modules/cli/Module.php',
]);
# modules/admin/Module.php 文件的view修正为
$di['view'] = function () {
    $view = new View();
    $view->setDI($this);
    $view->setViewsDir(__DIR__ . '/views/');

    $view->registerEngines([
        '.volt'  => 'voltShared',
        '.phtml' => PhpEngine::class
    ]);

    return $view;
};
.
├── bootstrap_cli.php
├── bootstrap_web.php
├── common
│   ├── library
│   │   └── TpDb.php
│   └── models
│       └── Order.php
├── config
│   ├── config.php
│   ├── loader.php
│   ├── routes.php
│   ├── services_cli.php
│   ├── services.php
│   └── services_web.php
└── modules
    ├── admin
    │   ├── controllers
    │   │   ├── BaseController.php
    │   │   └── IndexController.php
    │   ├── Module.php
    │   └── views
    ├── cli
    │   ├── migrations
    │   ├── Module.php
    │   └── tasks
    │       ├── MainTask.php
    │       └── VersionTask.php
    └── frontend
        ├── controllers
        │   ├── ControllerBase.php
        │   └── IndexController.php
        ├── Module.php
        └── views
            ├── index
            ├── index.phtml
            └── layouts
  • 模型使用redis缓存

## 注册 modelsCache,且配置statsKey默认为_PHCR

$di->setShared(
    'modelsCache',
    function () {
        // Cache data for one day (default setting)
        $frontCache = new \Phalcon\Cache\Frontend\Data(
            [
                'lifetime' => 86400,
            ]
        );

        // Memcached connection settings
        $cache = new \Phalcon\Cache\Backend\Redis(
            $frontCache,
            [
                'host' => '127.0.0.1',
                'port' => '6379',
                "auth" => "easyswoole",
                "index" => 0,
                'statsKey' => '_PHCR',
            ]
        );
        return $cache;
    }
);


## 使用
$ret = Order::query()
    ->where('id > :virtual:', ['virtual' => '1'])
    ->orderBy('id desc,userid asc')
    ->cache([
        'key' => 'order_list_' . time(),
    ])
    ->execute();
/**
    * @var array $ret 模糊查询,返回 key
    */
$ret = $this->modelsCache
    ->queryKeys("order_");
/**
    * @var mix $ret2 精确查询,返回 value
    */
$ret2 = $this->modelsCache
    ->get("order_list");
return $this->response->setJsonContent(['ret' => $ret, '$ret2' => $ret2]);
  • 多模块的视图

### 多模块的视图
/**
* 设置disableLevel,还是不要进行layout布局,每一个页面就是一个整体
*/
$di['view'] = function () {
    $view = new View();
    $view->setDI($this);
    $view->setViewsDir(__DIR__ . '/views/');
    $view->disableLevel(
        [
            View::LEVEL_MAIN_LAYOUT => true,
        ]
    );
    $view->registerEngines([
        '.volt'  => 'voltShared',
        '.phtml' => PhpEngine::class
    ]);
    return $view;
};


### 多模块渲染请指定文件名称
class IndexController extends \Demo\Modules\Admin\Controllers\BaseController
{
    public function loginAction()
    {
        return $this->view->pick('login');
    }
}
# /vagrant_data/test_lxx_mo/app/modules
.
└── admin
    ├── controllers
    │   ├── BaseController.php
    │   └── IndexController.php
    ├── Module.php
    └── views
        └── login.phtml
public function loginAction()
{
    /**
        * <input type='hidden' name='<?php echo $this->security->getTokenKey() ?>' value='<?php echo $this->security->getToken() ?>' />
        */
    if ($this->request->isPost()) {
        if (!$this->security->checkToken()) {
            $this->flashSession->error("checkToken err");
        } else {
            // ok
        }
    }
    return $this->view->pick('login');
}