如何将db adapter设置为Validator NoRecordExists并在控制器中使用它?

时间:2013-03-30 11:48:22

标签: zend-framework2

我最近开始学习ZF2并希望有人可以帮助我。

我正在通过Rob Allen的Zend Framework 2教程(非常感谢@ rob-allen)。

我也使用了@AlloVince和@Maciej How to set db adapter to Validator RecordExists in Zend Framework 2的解决方案(非常感谢两位作者)并且我感到困惑,因为我没有在 editAction 中使用此解决方案。 / p>

我在Fatal error: Call to a member function get() on a non-object中看到'adapter' => $this->getServiceLocator()->get('Zend\Db\Adapter\Adapter')

1)在Module.php中添加了

public function getServiceConfig()
{
    return array(
        'invokables' => array(
            'RegionModel' => 'FcLibraries\Model\Region', //<-- added it
        ),
        'factories' => array(
            'FcLibraries\Model\RegionTable' => function ($sm) {
                $dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
                $table = new RegionTable($dbAdapter);
                return $table;
            },
        ),
    );
}

2)在Region.php中添加了

/**
 * @var
 */
protected $serviceLocator;
/**
 * @param \Zend\ServiceManager\ServiceLocatorInterface $serviceLocator
 * @return Library
 */
public function setServiceLocator(ServiceLocatorInterface $serviceLocator)
{
    $this->serviceLocator = $serviceLocator;
    return $this;
}
/**
 * @return \Zend\ServiceManager\ServiceLocatorInterface
 */
public function getServiceLocator()
{
    return $this->serviceLocator;
}

        $inputFilter->add($factory->createInput(array(
            'name' => 'name',
            'required' => true,
            'filters' => $this->_filters,
            'validators' => array(
                array(
                    'name' => 'StringLength',
                    'options' => array(
                        'encoding' => 'UTF-8',
                        'min' => 1,
                        'max' => 30,
                    ),
                ),
                array(
                    'name'    => 'Db\NoRecordExists',
                    'options' => array(
                        'table' => $this->table,
                        'field' => 'name',
                        //'exclude' => array(
                        //    'field' => 'id',
                        //    'value' => $this->id
                        //),
                        'adapter' => $this->getServiceLocator()->get('Zend\Db\Adapter\Adapter'),
                    ),
                ),
            ),
        )));

3)在addAction中的RegionController.php中使用

  

$ model = $ this-&gt; getServiceLocator() - &gt; get('RegionModel');

而不是$model = new Region();

这适用于addAction,但我无法理解我应该如何在editAction中使用它。

public function editAction()
{
    $id = (int)$this->params()->fromRoute('id', 0);
    if (!$id) {
        return $this->redirect()->toRoute('zfcadmin/region', array(
            'action' => 'add'
        ));
    }
    $data = $this->getRegionTable()->get($id);
    $form = new RegionForm();
    $form->bind($data);
    $form->get('submitBtn')->setAttribute('value', 'Save');
    $request = $this->getRequest();
    if ($request->isPost()) {
        $form->setInputFilter($data->getInputFilter());
        $form->setData($request->getPost());
        if ($form->isValid()) {
            $this->getRegionTable()->save($form->getData());
            return $this->redirect()->toRoute('zfcadmin/regions');
        }
    }
    return array(
        'id' => $id,
        'form' => $form,
    );
}

我的RegionTable有以下代码:

/**
 * @param \Zend\Db\Adapter\Adapter $adapter
 */
public function __construct(Adapter $adapter)
{
    $this->adapter = $adapter;
    $this->resultSetPrototype = new ResultSet();
    $this->resultSetPrototype->setArrayObjectPrototype(new Region());
    $this->initialize();
}
public function get($id)
{
    $id = (int)$id;
    $rowSet = $this->select(array('id' => $id));
    $row = $rowSet->current();
    if (!$row) {
        throw new \Exception("Could not find row $id");
    }
    return $row;
}

非常感谢所有回答我问题的人。

最好的问候,鲁斯兰。

2 个答案:

答案 0 :(得分:3)

您应该通过服务管理器实例化一个新实体,而不是使用从表中收集的实体的表单过滤器来使用数据库适配器。

您有几个选择:

        
  1. 将输入过滤器移动到自己的类,并通过服务管理器实例化,以便注入数据库适配器。
  2.     
  3. 更改表网关工厂中的原型对象,以通过服务管理器工厂进行实例化。
  4.     
  5. 通过服务管理器实例化一个单独的实体,并从那里获取输入过滤器。
  6. 我个人会选择选项1,因为它可以更好地分离代码。

    一些例子:

    选项1(我的选择):

    这涉及将过滤器移动到自己的文件和类,在注入数据库适配器时为其创建工厂。然后,我们将在控制器中通过服务管理器获取过滤器并将过滤器应用于表单。

    首先将您的过滤器移动到ModName \ src \ ModName \ Form \ RegionFilter.php中的文件,显然用您的模块名称替换ModName。

    并将代码更改为:

    <?php
    namespace Region\Form;
    
    use Zend\InputFilter\Factory as InputFactory;
    use Zend\InputFilter\InputFilter;
    use Zend\InputFilter\InputFilterAwareInterface;
    use Zend\InputFilter\InputFilterInterface;
    use Zend\Db\Adapter\Adapter;
    
    class RegionFilter implements InputFilterAwareInterface {
    
        /**
         * @var inputFilter
         */
        protected $inputFilter;
    
        /**
         * @var Database Adapter
         */
        protected $dbAdapter;
    
        /**
         * @param \Zend\InputFilter\InputFilterInterface $inputFilter
         * @throws \Exception
         */
        public function setInputFilter(InputFilterInterface $inputFilter) {
            throw new \Exception("Not used");
        }
    
        /**
         * @param \Zend\Db\Adapter $dbAdapter
         */
        public function __construct(Adapter $dbAdapter) {
            $this->dbAdapter = $dbAdapter;
        }
    
        /**
         * 
         * @return Zend\Db\Adapter
         */
        public function getDbAdapter() {
            return $this->dbAdapter;
        }
    
        /**
         * @return \Zend\InputFilter\InputFilter
         * 
         * Get the input filter (build it first)
         */
        public function getInputFilter() {
            if (!$this->inputFilter) {
    
                $inputFilter = new InputFilter();
                $factory = new InputFactory();
    
                $inputFilter->add($factory->createInput(array(
                    'name' => 'name',
                    'required' => true,
                    'filters' => $this->_filters,
                    'validators' => array(
                        array(
                            'name' => 'StringLength',
                            'options' => array(
                                'encoding' => 'UTF-8',
                                'min' => 1,
                                'max' => 30,
                            ),
                        ),
                        array(
                            'name' => 'Db\NoRecordExists',
                            'options' => array(
                                'table' => $this->table,
                                'field' => 'name',
                                //'exclude' => array(
                                //    'field' => 'id',
                                //    'value' => $this->id
                                //),
                                'adapter' => $this->getDbAdapter(),
                            ),
                        ),
                    ),
                )));
                        $this->inputFilter = $inputFilter;
            }
    
            return $this->inputFilter;
        }
    }
    ?>
    

    然后你会在Module.php中创建一个这样的工厂:

    public function getServiceConfig()
    {
        return array(
            'factories' => array(
                'ModName\Form\RegionFilter' => function($sm) {
                    $dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
                    return new RegionFilter($dbAdapter);
                },
            ),
        );
    }
    

    最后在您的控制器中,只需执行以下操作:

    if ($request->isPost()) {
        $filter = $this->getServiceLocator()->get('ModName\Form\RegionFilter');
        $form->setInputFilter($filter->getInputFilter());
        $form->setData($request->getPost());
        if ($form->isValid()) {
            $this->getRegionTable()->save($form->getData());
            return $this->redirect()->toRoute('zfcadmin/regions');
        }
    }
    

    选项2:

    这涉及使用注入Region的实例构建表。然后你可以将原型设置为。

    所以在你的表格构造中:

    public function __construct(Adapter $adapter, Region $region)
    {
        $this->adapter = $adapter;
        $this->resultSetPrototype = new ResultSet();
        $this->resultSetPrototype->setArrayObjectPrototype($region);
        $this->initialize();
    }
    

    然后你的工厂:

    public function getServiceConfig()
    {
        return array(
            'invokables' => array(
                'RegionModel' => 'FcLibraries\Model\Region', 
            ),
            'factories' => array(
                'FcLibraries\Model\RegionTable' => function ($sm) {
                    $region = $sm->get('RegionModel');
                    $dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
                    $table = new RegionTable($dbAdapter,$region);
                    return $table;
                },
            ),
        );
    }
    

    您应该可以保留其余代码。比如控制器。现在我还没有测试过这种方法,所以我不是100%它会起作用,但我认为应该这样做。我以前用过的其他两种方法。

    选项3(最简单):

    这涉及通过服务管理器获取单独的区域模型,并使用该模型将输入过滤器应用于表单。

    public function editAction()
    {
        $id = (int)$this->params()->fromRoute('id', 0);
        if (!$id) {
            return $this->redirect()->toRoute('zfcadmin/region', array(
                'action' => 'add'
            ));
        }
        $data = $this->getRegionTable()->get($id);
        $form = new RegionForm();
        $form->bind($data);
        $form->get('submitBtn')->setAttribute('value', 'Save');
        $request = $this->getRequest();
        if ($request->isPost()) {
            $region = $this->getServiceLocator()->get('RegionModel');
            $form->setInputFilter($region->getInputFilter());
            $form->setData($request->getPost());
            if ($form->isValid()) {
                $this->getRegionTable()->save($form->getData());
                return $this->redirect()->toRoute('zfcadmin/regions');
            }
        }
        return array(
            'id' => $id,
            'form' => $form,
        );
    }
    

    我没有测试过代码,但你应该得到要点。有问题请问。

答案 1 :(得分:2)

要对“用户名是否已存在”进行验证,请执行以下简单的Service Manager配置设置:

// config / autoload / global.php

return array(
   'db' => array(
   'driver'   => 'Pdo',
   'dsn'      => 'mysql:dbname=zf2tutorial;host=localhost',
),

 'service_manager' => array(
   'factories' => array(
     'Zend\Db\Adapter\Adapter' => function ($serviceManager) {
        $adapterFactory = new Zend\Db\Adapter\AdapterServiceFactory();
           $adapter = $adapterFactory->createService($serviceManager);

           \Zend\Db\TableGateway\Feature\GlobalAdapterFeature::setStaticAdapter($adapter);

           return $adapter;
     }
  ),
)

);

并将以下数组添加到getInputFilter()中:

array(
  'table'   => 'users',
  'field'   => 'username',
  'adapter' => \Zend\Db\TableGateway\Feature\GlobalAdapterFeature::getStaticAdapter();
)