Cake PHP - 为应用程序创建某种mod

时间:2012-01-17 14:49:42

标签: php cakephp url-routing autoloader

我正在开发用CakePHP编写的外向专用项目,这个项目变得非常大。该架构也使用了一堆插件。从项目开始,该应用程序只有一个实例。但是客户发现应用程序可以工作的另一个区域。它将使用相同的代码库但是使用单独的数据库。事实上,代码库实际上适用于大约90%,这意味着在大多数情况下它将完成其工作,但是需要进行一些细微的更改。经过一些小的改进之后,很明显这些修改将继续用于这个新实例。但与此同时,两种情况都会有适用的变化。在整个应用程序中制作一堆条件并检查实际运行的实例是不是一个非常干净的解决方案。

所以我的想法是:

  • 将项目保存在一个存储库中,并对一个代码库中的所有实例进行更改和修复
  • 制作某种类型的“mod”,它将包含仅在需要时才会重载项目的默认类的类,并且只包含特定实例
  • 为了更清楚,最好将并行文件结构添加到将包含这些新类的app目录(当然只有那些需要的那些)
  • 非常重要的是根本不要碰蛋糕核心,我希望能够随时升级它而不会出现问题

示例:

app/controllers/invoices_controller.php:
InvoicesController extends AppController {
  public function generateInvoice() {}
}

newbusinness/controllers/invoices_controller.php:
NewbusinessInvoicesController extends InvoicesController {
  public function generateInvoice() {}
}

当我们去的时候,重要的是:

www.mynewbusinnes.com/Invoices/generateInvoice

系统会自动调用NewbusinessInvoicesController->generateInvoice(),因为存在这样的子控制器和方法。否则它将调用默认控制器和方法。

那么可以为CakePHP创建这样的模式,也许是在低级别的加载类上?我不想使用runkit_method_redefine()并替换App::import()方法,只要runkit_method_redefine()被标记为“实验”即可。有什么建议或想法吗?

2 个答案:

答案 0 :(得分:2)

  

那么可以为CakePHP创建这样的模式,也许是在低级别的加载类上?我不想使用runkit_method_redefine()并替换例如App :: import()方法,只要runkit_method_redefine()被标记为“experimental”。有什么建议或想法吗?

所有请求最初都通过app/webroot/index.php。此文件不是核心的一部分,可以自行修改。您可以做的是更改include paths以在CAKE_CORE_INCLUDE_PATH之前列出您自己创建的文件夹。在这里,我将/absolute/path/to/custom设置为包含路径:

if (function_exists('ini_set') && ini_set('include_path', ROOT . DS . 'custom' . PATH_SEPARATOR . CAKE_CORE_INCLUDE_PATH . PATH_SEPARATOR . ROOT . DS . APP_DIR . DS . PATH_SEPARATOR . ini_get('include_path'))) {

在本节之后,加载了CakePHP的核心引导程序文件(/cake/bootstrap.php),许多核心类开始加载:

require CORE_PATH . 'cake' . DS . 'basics.php';
$TIME_START = getMicrotime();
require CORE_PATH . 'cake' . DS . 'config' . DS . 'paths.php';
require LIBS . 'object.php';
require LIBS . 'inflector.php';
require LIBS . 'configure.php';
require LIBS . 'set.php';
require LIBS . 'cache.php';
Configure::getInstance();
require CAKE . 'dispatcher.php';

插入自己的包含路径后,您可以将它们复制到该路径来替换它们:

ROOT
|- app/
|- cake/
  |- libs/
    |- configure.php // this would usually be loaded
|- custom/
  |- cake/
    |- libs/
      |- configure.php // now this is loaded

(注意:configure.php文件包含ConfigureApp类。)

简而言之,通过更改app/webroot/index.php中的单行,您现在可以替换CakePHP核心的任何部分,而无需直接编辑它。

您现在可以对App::import进行必要的更改,但由于实际上没有在任何地方记录,您的里程可能会有所不同。

答案 1 :(得分:1)

  

所以我的想法是:

     
      
  • 将项目保存在一个存储库中,并对一个代码库中的所有实例进行更改和修复
  •   
  • 制作某种类型的“mod”,它将包含仅在需要时才会重载项目的默认类的类,并且只包含特定实例
  •   
  • 为了更清楚,最好将并行文件结构添加到将包含那些新类的app目录(当然只有那些需要的那些) - 非常重要的是根本不要碰蛋糕核心,我希望能够随时升级它而不会出现问题
  •   

我在previous answer中提到了这一点,但additional class paths听起来可能就像你正在寻找的CakePHP功能。您的“mod”应用程序bootstap.php中的以下内容应该告诉CakePHP也从core目录加载文件:

App::build(array(
    'plugins'     => array(ROOT . DS . 'core' . DS . 'plugins' . DS),
    'models'      => array(ROOT . DS . 'core' . DS . 'models' . DS),
    'views'       => array(ROOT . DS . 'core' . DS . 'views' . DS),
    'controllers' => array(ROOT . DS . 'core' . DS . 'controllers' . DS),
    'datasources' => array(ROOT . DS . 'core' . DS . 'models' . DS . 'datasources' . DS),
    'behaviors'   => array(ROOT . DS . 'core' . DS . 'models' . DS . 'behaviors' . DS),
    'components'  => array(ROOT . DS . 'core' . DS . 'controllers' . DS . 'components' . DS),
    'helpers'     => array(ROOT . DS . 'core' . DS . 'views' . DS . 'helpers' . DS),
    'vendors'     => array(ROOT . DS . 'core' . DS . 'vendors' . DS),
    'shells'      => array(ROOT . DS . 'core' . DS . 'vendors' . DS . 'shells' . DS),
    'locales'     => array(ROOT . DS . 'core' . DS . 'locale' . DS),
));

上面假设一个新的文件夹结构,而不是/app/cake,如下所示:

- ROOT
|- app1 // look here first,
|- app2
|- core // then here,
|- cake // then lastly here.