2

i got a problem regarding Unit-testing a Zend-Framework application under Ubuntu 12.04. The project-structure is a default zend application whereas the models are defined as the following

./application
  ./models
    ./DbTable
      ./ProjectStatus.php (Application_Model_DbTable_ProjectStatus)
    ./Mappers
      ./ProjectStatus.php (Application_Model_Mapper_ProjectStatus)
    ./ProjectStatus.php   (Application_Model_ProjectStatus)

The Problem here is with the Zend-specific autoloading. The naming convention here appears that the folder Mappers loads all classes with _Mapper but not _Mappers. This is some internal Zend behavior which is fine so far.

On my windows machine the phpunit runs without any Problems, trying to initiate all those classes.

On my Ubuntu machine however with jenkins running on it, phpunit fails to find the appropriate classes giving me the following error

Fatal error: Class 'Application_Model_Mapper_ProjectStatus' not found 
in /var/lib/jenkins/jobs/PAM/workspace/tests/application/models/Mapper/ProjectStatusTest.php
on line 39

The error appears to really be that the Zend-Autoloader doesn't load from the ubuntu machine, but i can't figure out how or why this works. The question remains of why this is. I think i've double checked every point of contact with the zend autoloading stuff, but i just can't figure this out. I'll paste the - from my point of view relevant snippets - and hope someone of you has any insight to this.

Jenkins Snippet for PHPUnit

 <target name="phpunit" description="Run unit tests with PHPUnit">
   <exec executable="phpunit" failonerror="true">
     <arg line="--configuration '${basedir}/tests/phpunit.xml' --coverage-clover '${basedir}/build/logs/clover.xml' --coverage-html '${basedir}/build/coverage/.' --log-junit '${basedir}/build/logs/junit.xml'" />
   </exec>
 </target>

./tests/phpunit.xml

<phpunit bootstrap="./bootstrap.php">
   ... this shouldn't be of relevance ...
</phpunit>

./tests/bootstrap.php

<?php
// Define path to application directory
defined('APPLICATION_PATH')
    || define('APPLICATION_PATH', realpath(dirname(__FILE__) . '/../application'));

// Define application environment
defined('APPLICATION_ENV')
    || define('APPLICATION_ENV', (getenv('APPLICATION_ENV') ? getenv('APPLICATION_ENV') : 'testing'));

// Ensure library/ is on include_path
set_include_path(implode(PATH_SEPARATOR, array(
    realpath(APPLICATION_PATH . '/../library'),
    get_include_path(),
)));

require_once 'Zend/Loader/Autoloader.php';    
Zend_Loader_Autoloader::getInstance();

Any help will be appreciated.

4

3 回答 3

2

我实际上认为问题在于您的“模型/映射器”文件夹。它应该是“模型/映射器”(全部小写),并解释为什么它可以在 Windows 而不是 Linux 上工作。

从 Zend_Application_Module_Autoloader 类可以看出:

$this->addResourceTypes(array(
            'dbtable' => array(
                'namespace' => 'Model_DbTable',
                'path'      => 'models/DbTable',
            ),
            'mappers' => array(
                'namespace' => 'Model_Mapper',
                'path'      => 'models/mappers',
            ),

但是,根据我之前的回答,我仍然相信您需要引导应用程序才能自动添加所有默认资源

于 2012-07-03T14:55:24.763 回答
1

从采埃孚手册:

创建模型和数据库表

在我们开始之前,让我们考虑一些事情:这些类将放在哪里,我们将如何找到它们?我们创建的默认项目实例化了一个自动加载器。我们可以将其他自动加载器附加到它,以便它知道在哪里可以找到不同的类。通常,我们希望将各种 MVC 类分组在同一棵树下——在本例中为 application/——并且通常使用公共前缀。

Zend_Controller_Front有一个“模块”的概念,它们是单独的迷你应用程序。模块模仿 zf 工具在 application/ 下设置的目录结构,并且假定其中的所有类都以一个公共前缀开头,即模块名称。application/ 本身就是一个模块——“默认”或“应用程序”模块。因此,我们需要为该目录​​中的资源设置自动加载。

Zend_Application_Module_Autoloader提供将模块下的各种资源映射到适当目录所需的功能,并提供标准命名机制。默认情况下,在 bootstrap 对象的初始化过程中会创建一个类的实例;默认情况下,您的应用程序引导程序将使用模块前缀“Application”。因此,我们的模型、表单和表格类都将以类前缀“Application_”开头。

由于 Zend_Application_Module_Autoloader 是默认加载的,因此您只需要按照此答案中的示例引导您的应用程序(您不必运行前端控制器)。

如果您不想引导您的应用程序,您可以通过自己初始化 Zend_Application_Module_Autoloader 来缩短资源加载:

$autoloader = new Zend_Application_Module_Autoloader();

从代码中可以看出,此类的 __construct 调用了 initDefaultResourceTypes(),其中包含您正在寻找的所有好处:

class Zend_Application_Module_Autoloader extends Zend_Loader_Autoloader_Resource
{
    /**
     * Constructor
     *
     * @param  array|Zend_Config $options
     * @return void
     */
    public function __construct($options)
    {
        parent::__construct($options);
        $this->initDefaultResourceTypes();
    }

    /**
     * Initialize default resource types for module resource classes
     *
     * @return void
     */
    public function initDefaultResourceTypes()
    {
        $basePath = $this->getBasePath();
        $this->addResourceTypes(array(
            'dbtable' => array(
                'namespace' => 'Model_DbTable',
                'path'      => 'models/DbTable',
            ),
            'mappers' => array(
                'namespace' => 'Model_Mapper',
                'path'      => 'models/mappers',
            ),
            'form'    => array(
                'namespace' => 'Form',
                'path'      => 'forms',
            ),
            'model'   => array(
                'namespace' => 'Model',
                'path'      => 'models',
            ),
            'plugin'  => array(
                'namespace' => 'Plugin',
                'path'      => 'plugins',
            ),
            'service' => array(
                'namespace' => 'Service',
                'path'      => 'services',
            ),
            'viewhelper' => array(
                'namespace' => 'View_Helper',
                'path'      => 'views/helpers',
            ),
            'viewfilter' => array(
                'namespace' => 'View_Filter',
                'path'      => 'views/filters',
            ),
        ));
        $this->setDefaultResourceType('model');
    }
}

在 tests/bootstrap.php 中仅引导您的应用程序而不运行前端控制器:

<?php
// Define path to application directory
defined('APPLICATION_PATH')
    || define('APPLICATION_PATH', realpath(dirname(__FILE__) . '/../application'));

// Define application environment
defined('APPLICATION_ENV')
    || define('APPLICATION_ENV', (getenv('APPLICATION_ENV') ? getenv('APPLICATION_ENV') : 'testing'));

// Ensure library/ is on include_path
set_include_path(implode(PATH_SEPARATOR, array(
    realpath(APPLICATION_PATH . '/../library'),
    get_include_path(),
)));

require_once 'Zend/Loader/Autoloader.php';  

$config = array(
    APPLICATION_PATH . '/configs/application.ini'
);

// Create application, bootstrap, and run
$application = new Zend_Application(
    APPLICATION_ENV,
    array('config' => $config)
);

$application->bootstrap();
于 2012-07-03T07:42:56.117 回答
0

由于传统的 Autoloader 不起作用,我尝试手动执行任何 Zend 应用程序会执行的操作。这是bootstrap.php最终解决的问题

<?php    
// Define path to application directory
defined('APPLICATION_PATH')
    || define('APPLICATION_PATH', realpath(dirname(__FILE__) . '/../application'));

// Define application environment
defined('APPLICATION_ENV')
    || define('APPLICATION_ENV', (getenv('APPLICATION_ENV') ? getenv('APPLICATION_ENV') : 'testing'));

// Ensure library/ is on include_path
set_include_path(implode(PATH_SEPARATOR, array(
    realpath(APPLICATION_PATH . '/../library'),
    get_include_path(),
)));

require_once 'Zend/Loader/Autoloader.php';
require_once 'Zend/Loader/Autoloader/Resource.php';
$resources = new Zend_Loader_Autoloader_Resource(array(
  'namespace' => 'Application',
  'basePath'  => APPLICATION_PATH
));

$resources->addResourceType('form','forms','Form');
$resources->addResourceType('model','models','Model');
$resources->addResourceType('dbtable','models/DbTable','Model_DbTable');
$resources->addResourceType('mapper','models/Mappers','Model_Mapper');

逻辑通常是 Zend 自己应该弄清楚的。事实上,它是在我在 Windows 上运行的本地开发机器上执行的。然而,在 ubuntu 上,我需要变得具体。

知道为什么会很有趣。如果有人可以向我解释原因,那么我可能最终会给你正确的答案;)

于 2012-07-03T08:02:32.400 回答