在Lithium应用程序上设置多个webroot环境的最佳做法是什么?

时间:2014-04-05 15:25:18

标签: php lithium

我有兴趣为多个用户提供统一的后端环境,并为用户提供多个前端环境。所有应该从单个应用程序实例运行,该实例将等同于app文件夹。我已经在几种配置上来回走动,但是一旦我深入了解应用程序,就会遇到不一致的问题。想象一下像企业WordPress应用程序:用户需要一个独特的webroot为他们的帐户访问他们的模板和数字资产,但一个应用程序实例为所有用户运行后端环境。这在锂电池上证明是棘手的。

现在,我在/[user]/webroot/index.php文件中设置了一个基本环境参数,如下所示:

<?php

$env = ['webroot' => __DIR__, 'id' => 'generic_account'];

require dirname(dirname(__DIR__)) . '/app/config/bootstrap.php';

use lithium\action\Dispatcher;
use lithium\action\Request;

echo Dispatcher::run(new Request(compact('env')));

?>

然后,在Dispatcher中,我有一个扩展类映射帐户:

Dispatcher::applyFilter('run', function($self, $params, $chain) use (&$i) {
    Environment::set($params['request']);

    //Map $env['id'] value to stored database connection
    if (isset($params['request']->id)) {
        Accounts::load($params['request']);
    }

    foreach (array_reverse(Libraries::get()) as $name => $config) {
        if ($name === 'lithium') {
            continue;
        }
        $file = $config['path'] . '/config/routes.php';
        file_exists($file) ? call_user_func(function() use ($file) { include $file; }) : null;
    }
    return $chain->next($self, $params, $chain);
});

最后,在Accounts::load()方法中,我从主数据库中提取连接设置并将其设置为默认的连接配置:

<?php

namespace app\extensions\core;

use app\models\Routes;
use lithium\net\http\Router;

class Accounts {

    public static function load(&$request) {
        if (!is_object($request)) {
            return false;
        }
        $class = [
            'accounts'      => 'app\models\Accounts',
            'plugins'       => 'app\extensions\core\Plugins',
            'prefs'         => 'app\extensions\core\Preferences',
            'connections'   => 'lithium\data\Connections',
            'inflector'     => 'lithium\util\Inflector',
            'exception'     => 'lithium\net\http\RoutingException'
        ];
        $class['accounts']::meta('connection', 'master');
        $bind = $class['prefs']::read('bind_account');
        $key = $bind == 'domain' || $bind == 'subdomain' ? 'HTTP_HOST' : 'id';
        $find = $class['accounts'] . '::' . $class['inflector']::camelize('find_by_' . $bind, false);
        $account = call_user_func($find, $request->env($key));

        if ($account == null) {
            throw new $class['exception']('Account `' . $request->env($key) . '` doesn\'t exist.');
        }
        $class['connections']::add('default', json_decode($account->database, true));
        $request->activeAccount = $account;
        $request->params['webroot'] = $request->env('webroot');
        $plugins = $class['plugins']::load();
        return true;
    }

    /**
     * Allows users to store customized route definitions in `routes` table,
     * hence the use of `app\models\Routes`.
     */
    public static function routes() {
        $routes = Routes::all();
        foreach ($routes as $route) {
            Router::connect($route->match, [
                'controller' => 'pages',
                'action' => 'view',
                'template' => $route->template,
                'layout' => $route->layout
            ]);
        }
    }
}

?>

所有这些似乎都适用于路由URL并允许多个前端webroots。这就是诀窍:当为管理界面创建一个webroot时,它会变成一个令人费解的混乱,以保持资产路径的直线。我曾使用Media::assets()试图克服这个问题,但我觉得那里有更优雅的解决方案。我很难找到专门解决这种设置问题的任何其他示例或文档。

2 个答案:

答案 0 :(得分:2)

这很简单,你几乎就在那里。您真正需要的是每个用户唯一的webroot/目录,除了正常的bootstrap include和request-dispatching之外,您还可以包含任何其他特定于用户的配置,并注册主应用程序,如下所示:

Libraries::add('yourApp', [ 'path' => '/path/to/codebase', 'webroot' => __DIR__ ]);

这为您提供了集中式代码库,但也允许每个用户使用自定义Webroro。

答案 1 :(得分:0)

我有两个锂电池平台,设置类似。我写了一个名为li3_saas的插件来促进它,我认为我仍然需要在github上。但它在从主数据库加载并将默认数据库设置为用户特定的情况下做了类似的事情。

我建议使用全局管理界面完全不同的应用程序,可以使用Libraries::add()加载主应用程序,可能使用'bootstrap => false选项跳过加载引导程序。

我完成了一些事情 - 比如重用css或js - 在文件系统上使用符号链接。

我确实使用Media::assets()让我的管理界面知道上传文件的存在位置。我在那里创建了一个名为“上传”的自定义密钥。并在创建资产路径和网址时使用它。

我可以详细说明。你能给出一个你想要解决的更具体的用例吗?