数据映射器,控制器和模型的Zend框架结构

时间:2011-07-21 11:34:50

标签: zend-framework

我刚开始使用Zend Framework,所以我对结构有很多疑问。 我希望我能正确解释,这很难。

好的,我已经完成了快速入门教程,并决定在我的第一个项目中使用类似的结构。

所以我有一个Datamapper,一个Model和一个数据库表文件。

我创建了一个表单,我可以在其中输入一些信息(项目)并用它上传图像。

我有2个Datamapper(项目和图像)以及2个模型。我有一个Item Controller,跳转到ItemMapper。在Datamapper中,我有一个save方法。请参阅以下内容:

 public function save(Application_Model_Item $item)
{

    $data = array(
           'item_title'        => $item->getItemTitle(),
           'item_description'  => $item->getItemDescription(),
            );
    $this->getDbTable()->insert($data);

    // Add Image Information ($imageData is Session Data) 
    $table  = new Application_Model_DbTable_Image();
    foreach ($imageData as $fileData)
    { 
        $image = new Application_Model_Image($fileData);
        $data = array(  
              'image_newname'   => $image->getNewImageName(),
              'image_thumbname' => $image->getImageThumbName(),      
            );
        $table->insert($data);
     }

现在我有问题了。

  1. 我的模型中有Getter和Setter。如果项目数据库表中的所有内容都在1个模型中吗?意味着关于Image的所有内容应该转到图像模型,因为它位于不同的数据库表中?
  2. 在项目映射器中保存有关图像的信息是否正确? Shoudl我在ImageMapper中没有save()方法并将其保存在那里?如果是这样,我如何从Item Mapper跳转到Image Mapper?或者我会先完成有关Item的所有内容,将ID返回给Controller,然后从Controller调用ImageMapper?
  3. 我读了一些关于“Fat Model Thin Controller”的内容。我一直都有这个,但是我注意到我的控制器非常胖,只需将Form放在一起。我有大约5个下拉字段,这取决于下拉列表。当我看到我复制Code时,我决定将它添加到一个单独的Function中。所以f.e.我有一个县的下拉菜单。我写了一个函数,它也在我的控制器中,所以它看起来像这样:

    public function getCounties ()
    

    {

    // List of Counties does not exist in Cache, read from DB
        if(!$CountyList = $this->getFromCache('counties')){
    
        $geolocationMapper = new Application_Model_GeolocationMapper();
        $CountyDropdown = $geolocationMapper->createCountyDropdown();
    
        // Save DB Result in Cache
        $this->addToCache ('counties',$CountyDropdown);
        return $CountyDropdown;
    }
    else{
        // Return Country List from Cache
        return $this->getFromCache('counties');            
    }   
    

    }

  4. 在我的添加功能中,我使用

    //将地理信息分配给表单

    $CountyList = $this->getCounties();               
    $form->getElement('county')->setMultiOptions($CountyList);   
    

    编辑功能

    $CountyList = $this->getCounties();
    $form->getElement('county')->setMultiOptions($CountyList)->setValue($activeCounty)
    

    getCounties()等所有函数都保留在Controller中,还是应该移动到GeolocationMapper?如果是这样,那怎么会被召唤出来?

    1. 是否应该在某个函数中创建表单,所以我只会调用类似createForm()的东西?我真的有很多重复(添加和编辑功能),而且来自数据库或表单的Stuff无效,它来自带有setValue的Cache。它只是在使用可靠的Dropdown时加起来。
    2. 我知道这是很多问题,但我觉得它变得非常混乱,作为一个学习者,当它工作时你很开心,但我也希望以适当的方式构建它。我希望这一切都有道理。

      也许有些人有一些我可以使用的Tipps。非常感谢您的帮助。

2 个答案:

答案 0 :(得分:1)

这里有很多问题,大多数答案主要取决于个人偏好。有了这个警告:

  

项目数据库表中的所有内容是否应该在1个模型中?

我会说是的,尽管一般来说,从模型的角度而不是数据库结构中尝试思考它。因此,所有'item'数据都在Item模型中 - 事实上,这一切都存储在一个数据库表中是无关紧要的,因为映射器处理从一个到另一个的转换。

  

在项目映射器中保存有关图像的信息是否正确?

不清楚你的示例中$ imageData来自哪里,但是如果有要保存的图像数据,我会说Item映射器应该调用Image映射器,例如:

public function save(Application_Model_Item $item)
{
    $data = array(
        'item_title'        => $item->getItemTitle(),
        'item_description'  => $item->getItemDescription(),
    );
    $this->getDbTable()->insert($data);

    // save image data if present
    if (isset($item->image)) {
        $imageMapper = new Yourapp_Mapper_Image();
        $imageMapper->save($item->image);
    }

    return true;
}
  

[应该]像getCounties()这样的所有函数都保留在Controller中,还是应该移动到GeolocationMapper?如果是这样,那怎么会被召唤出来?

我认为这些功能没有任何理由在控制器中。根据您对Zend_Form组件的满意程度,一种方法可能是编写扩展Yourapp_Form_Element_Counties的自定义Zend_Form_Element_Select类。然后,将逻辑从getCounties函数移动到此类中,因此表单元素本身负责填充它所呈现的选项。 E.g:

class Yourapp_Form_Element_Counties extends Zend_Form_Element_Select
{
    public function getMultiOptions()
    {
        // load counties here and return an array in the format key -> value
    }
}

另一种方法,如果你有很多与位置相关的表单元素,可能是创建一个GeoLocation Service类,它具有返回选项的县,城市等功能。

  

如果在某个函数中创建表单,那么我只会调用类似createForm()

的内容

目前还不清楚你在控制器中做了多少表单,除了填充选择选项之外,所以很难回答这个问题。以下是我在使用Zend_Form时通常遵循的原则:

  • 每个表单都有自己的类,扩展Zend_Form(或Zend_Dojo_Form),它存在于application / forms中,名为Myapp_Form _ *
  • 每个表单类都在init()方法中设置它的元素(Zend_Form的构造函数为此目的自动调用它)。
  • 如果我发现在不同的操作中我需要对同一个表单稍作变化(例如在添加和编辑操作中),我会为表单(例如Myapp_Form_Post_Base)创建一个抽象基类来定义元素,并且然后是特定于行动的类,它们扩展了它:Myapp_Form_Post_AddMyapp_Form_Post_Edit等等。这些类在他们自己的init()方法中对基本表单进行所需的任何更改。

我的行为看起来像这样:

public function editAction()
{
    $form = new Myapp_Form_Post_Edit();

    if ($this->_request->isPost()) {
        if ($form->isValid($this->_request->getPost()) {
            // save data, set flash messge and redirect
        }
    }

    $this->view->form = $form;
}

我唯一的另一条建议是尝试遵循对您来说最合乎逻辑的方法。您可能会发现很难找到确定的“最佳实践”,因为有很多不同的方法可以做到这一切。

答案 1 :(得分:0)

我试图尽可能地遵循你的想法,所以所有对县,镇和邮政编码的调用都在GeolocationMapper中,图像数据的保存在ImageMapper中。

你问我现在如何创建我的表格,这是一个来自县表格的init()等的例子......

  // Create Dropdown for Counties          
    $county = new Zend_Form_Element_Select('county');      
    $county->setLabel('Select a County')
           ->setRegisterInArrayValidator(false) 
       ->setDecorators(array(
        'ViewHelper',
        'Errors',
              array('Description', 
                      array('tag' => 'p', 'class'=>'description')),         
                    'Label',
              array('HtmlTag',
              array('tag'=>'li','class'=>'county'))                 
             ))  
           ->setRequired(false);

    // Create Dropdown for Town
    $town = new Zend_Form_Element_Select('town');
    $town->setRegisterInArrayValidator(false)
         ->setDecorators(array(
                            'ViewHelper',
                            'Errors',
                            array('Description', array('tag' => 'p', 'class' => 'description')),
                            'Label',
                            array('HtmlTag',array('tag'=>'li','class'=>'town'))
                            ));  


    // Create Dropdown for Postcode
    $postcode = new Zend_Form_Element_Select('postcode');
    $postcode->setRegisterInArrayValidator(false)
             ->setDecorators(array(
                            'ViewHelper',
                            'Errors',
                            array('Description', array('tag' => 'p', 'class' => 'description')),
                            'Label',
                            array('HtmlTag',array('tag'=>'li','class'=>'postcode'))
                            )) 
             ->setRegisterInArrayValidator(false);

在我的控制器中我获取元素并填充它们:

$geolocationMapper = new Application_Model_GeolocationMapper();
$CountyOptions = $geolocationMapper->createCountyDropdown();
$form->getElement('county')->setMultiOptions($CountyOptions);

在我的GeolocationMapper中,我有构建我的县数组的方法:

/** ===========================================================================
* Get Counties
* @param 
* @return Object? of Counties  
* ========================================================================= */   

public function getCountyList()
{
        $table = $this->getDbTable();

        $select = $table->select()->distinct()
                  ->from(array('p' => 'geolocation'),'county')
                  ->order('county');
        $resultSet = $this->getDbTable()->fetchAll($select);
        $entries   = array();
        foreach ($resultSet as $row)
        {
            $entry = new Application_Model_Geolocation();
            $entry->setId($row->county)
                  ->setCounty($row->county);   
            $entries[] = $entry;
        }
        return $entries;    
}     



/** ===========================================================================
* Create Array which will be used for Dropdown
* @param 
* @return Array of Counties  
* ========================================================================= */   

public function createCountyDropdown()
{

    // List of Counties does not exist in Cache, read from DB
    if(!$CountyList = $this->getFromCache('counties'))
    {               
        $CountyList = $this->getCountyList();
        $Counties[''] = "Please choose";

        foreach($CountyList as $value)
        {
             $Counties[str_replace(' ','_',$value->getCounty())] = $value->getCounty();
        }

        $CountyDropdown = $Counties;

        // Save DB Result in Cache
        $this->addToCache ('counties',$CountyDropdown);
        return $CountyDropdown;

    }else{
        return $this->getFromCache('counties');     
    }

}

我在GeolocationMapper中读到的县。当您选择一个郡时,Towns和Postcodes会被读取,而不是通过Ajax调用地理位置映射器而不是createTownDropdown($ county),当一个城镇选择相同的过程但是调用loadPostcodes()的Ajax时,还有createPostcodeDropdown($ town) )。

这一切听起来是否正确或有任何建议我如何改善这一点?

我很抱歉,但我真的想添加另一个问题,因为我无法在任何地方找到答案...我还有一个图像上传,可以通过Ajax和jQuery工作。选择要上载的图像时,图像会直接显示。为此我动态创建一个带有图像src的输入元素。我没有找到其他方式将图像添加到Zend Form。是否有可能添加图像以正常显示图像?拥有一个img会更容易,因为我想使用jQuery Drag and Drop。非常感谢你们的帮助!