Zend Framework 2 Db Validator Zend \ Validate \ Db \ NoRecordExists - 我不能让事情对我有用

时间:2014-01-03 22:26:16

标签: database forms validation zend-framework2

我一直在寻找,找到了一些"解决方案"对此,有些人甚至让我重写了我的大部分InputFilter并在我的Module.php和/或module.config.php中添加了很多东西......没有任何运气......只是无法做到它对我有用,仍然有各种各样的错误。 我决定撤消所有内容并从头开始(我的代码最初看起来的方式,然后再根据数据库验证表单条目)并在此处提出我的问题。

我正在进行注册过程。 当然,我需要根据用户表中的现有记录验证电子邮件地址(不应该允许2个相同的电子邮件地址)。 当然,在我的数据库中,我将该列设置为仅接受唯一值...但在实际对数据库执行任何操作之前,我还必须验证它并在表单提交上向用户提供相应的消息。

如何使用Db \ NoRecordExists(或任何其他Db验证器)? 我应该在代码中进一步编写什么(添加/编辑)? 我已粘贴下面的所有代码。 我需要添加Db \ NoRecordExists验证器的表单元素是' user_identifier'。

这是我的/config/autoload/global.php:

return array(
    'db' => array(
        'driver' => 'Pdo',

        'dsn' => 'mysql:dbname=my_database_name;host=localhost',
        'username' => 'my_user',
        'password' => 'my_password',

        'driver_options' => array(
            PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES \'UTF8\'',
        ),
    ),

    'service_manager' => array(
        'factories' => array(
            'Zend\Db\Adapter\Adapter' => 'Zend\Db\Adapter\AdapterServiceFactory',
        ),
    ), 
);

这是我的注册表格(/module/User/src/User/Form/RegisterForm.php):

namespace User\Form;

use Zend\Form\Form;

class RegisterForm extends Form {

    public function __construct() {
        parent::__construct('register');

        $this->setHydrator(new \Zend\Stdlib\Hydrator\Reflection());
        $this->setObject(new \User\Entity\Users());

        $this->setAttributes(array(
            // not important for my issue
        ));
        $this->setInputFilter(new \User\Form\RegisterFilter);

        // User Identifier
        $identifier = new \Zend\Form\Element\Email();
        $identifier->setName('user_identifier');
        $identifier->setAttributes(array(
            'id' => 'user-email',
            'placeholder' => 'Email',
            'class' => 'form-control'
        ));
        $identifier->setLabel('Your email:');

        /*
         * Many other fields were here, but to make the sample code
         * shorter here, I've only left one of the fields I need to
         * validate against the database
         */

        $this->add($identifier); // User's email - used for login

        // Submit
        $this->add(array(
            'name' => 'submit',
            'attributes' => array(
                'type' => 'submit',
                'value' => 'Register',
                'class' => 'btn btn-primary',
            ),
        ));
    }
}

这是我的RegisterFilter(/module/User/src/User/Form/RegisterFilter.php):

namespace User\Form;

use Zend\Form\Form;
use Zend\InputFilter\InputFilter;

use Zend\InputFilter\InputFilterAwareInterface;
use Zend\InputFilter\InputFilterInterface;
use Zend\Db\Adapter\Adapter;

class RegisterFilter extends InputFilter {

    public function __construct() {

        // User Identifier (Email)
        $this->add(array(
            'name' => 'user_identifier',
            'required' => true,
            'filters' => array(
                array('name' => 'StringTrim'),
            ),

            'validators' => array(
                /*
                 * Some validators here (NotEmpty, EmailAddress)
                 */

                array(
                    'name' => 'Db\NoRecordExists',
                    'options' => array(
                        'table' => 'users',
                        'field' => 'user_identifier',
                        /*
                         * 'adapter' => had many examples for what to put here, like:
                         * \Zend\Db\TableGateway\Feature\GlobalAdapterFeature::getStaticAdapter()
                         * and for that I also had to put:
                            'Zend\Db\Adapter\Adapter' => function ($sm) {
                                $adapterFactory = new Zend\Db\Adapter\AdapterServiceFactory();
                                $adapter = $adapterFactory->createService($sm);
                                \Zend\Db\TableGateway\Feature\GlobalAdapterFeature::setStaticAdapter($adapter);
                                return $adapter;
                            }
                         * in my /config/autoload/global.php (and can't remember anything else) BUT, while
                         * following the example to the letter, I still got errors (like "no static adapter blah-blah - can't remember) and didn't work
                         * and so on... followed quite a few different examples/methods, rewrote/added many lines in my code
                         * (in the Model and/or Controller and/or Module.php) but still couldn't make things work for me.
                         */
                    ),
                ),
            ),
        ));

        /*
         * Filters and validators for the rest of the form elements here
         * Removed them so I would keep the code focused on my question
         */
    }
}

这是我的用户模块的Module.php(/module/User/Module.php):

namespace User;

use User\Entity\Users;
use User\Entity\UsersTable;
use Zend\Db\ResultSet\ResultSet;
use Zend\Db\TableGateway\TableGateway;

class Module {

    public function getAutoloaderConfig() {
        // ...
    }

    public function getConfig() {
        // ...
    }

    public function getViewHelperConfig() {
        // ...
    }

    public function getServiceConfig() {
        return array(
            'factories' => array(
                'User\Entity\UsersTable' => function($sm) {
                    $tableGateway = $sm->get('UsersTableGateway');
                    $table = new UsersTable($tableGateway);
                    return $table;
                },
                'UsersTableGateway' => function($sm) {
                    $dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
                    $resultSetPrototype = new ResultSet();
                    $resultSetPrototype->setArrayObjectPrototype(new Users());
                    return new TableGateway('users', $dbAdapter, null, $resultSetPrototype);
                },
            ),
        );
    }
}

这是我的模型(/module/User/src/User/Entity/Users.php):

namespace User\Entity;

class Users {

    public $user_id;
    public $other_id;
    public $user_identifier;
    public $user_credential;
    public $user_type;
    public $user_alias;
    public $active;
    public $enabled;
    public $token;
    public $created;

    public function exchangeArray($data) {
        $this->user_id = (isset($data['user_id'])) ? $data['user_id'] : null;
        $this->other_id = (isset($data['other_id'])) ? $data['other_id'] : 0;
        $this->user_identifier = (isset($data['user_identifier'])) ? $data['user_identifier'] :  'what?';
        $this->user_credential = (isset($data['user_credential'])) ? md5($data['user_credential']) : 'not-possible';
        $this->user_type = (isset($data['user_type'])) ? $data['user_type'] : 'client';
        $this->user_alias = (isset($data['user_alias'])) ? $data['user_alias'] : 'Anonymus';
        $this->active = (isset($data['active'])) ? $data['active'] : 0;
        $this->enabled = (isset($data['enabled'])) ? $data['enabled'] : 1;
        $this->token = (isset($data['token'])) ? $data['token'] : 'no-token';
        $this->created = (isset($data['created'])) ? $data['created'] : date('Y-m-d h:m:s', time());
    }

    public function getArrayCopy() {
        return get_object_vars($this);
    }
}

和TableGateway(/module/User/src/User/Entity/UsersTable.php):

namespace User\Entity;

use Zend\Db\TableGateway\TableGateway;

class UsersTable {

    protected $tableGateway;

    public function __construct(TableGateway $tableGateway) {
        $this->tableGateway = $tableGateway;
    }

    /*
     * fetchAll(), getUserById(), deleteUser() etc.
     * Different methods here...
     */

    public function saveUser(Users $user) {
        $data = array(
            'user_id' => $user->user_id,
            'other_id' => $user->other_id,
            'user_identifier' => $user->user_identifier,
            'user_credential' => $user->user_credential,
            'user_type' => $user->user_type,
            'user_alias' => $user->user_alias,
            'active' => $user->active,
            'enabled' => $user->enabled,
            'token' => $user->token,
            'created' => $user->created
        );

        $user_id = (int)$user->user_id;
        if ($user_id == 0) {
            $this->tableGateway->insert($data);
        } else {
            if ($this->getUser($user_id)) {
                $this->tableGateway->update($data, array('user_id' => $user_id));
            } else {
                throw new \Exception("User with id {$user_id} does not exist");
            }
        }
    }
}

最后,但并非最不重要的是,这是我的控制器(/module/User/src/User/Controller/IndexController.php):

namespace User\Controller;

use Zend\Mvc\Controller\AbstractActionController;
use Zend\View\Model\ViewModel;

use User\Entity\Users;

class IndexController extends AbstractActionController {

    public function registerAction() {

        $registerForm = new \User\Form\RegisterForm;

        if ($this->getRequest()->isPost()) {
            // Form processing
            $formData = $this->getRequest()->getPost();
            $registerForm->setData($formData);

            if ($registerForm->isValid()) {
                // Insert into DB here
                $user = new Users();
                $user->exchangeArray($formData->user);
                $this->getUsersTable()->saveUser($user);
            }
            return new ViewModel(array(
                'form' => $registerForm,
            ));
        } else {
            return new ViewModel(array(
                'form' => $registerForm,
            ));
        }
    }

    /*
     * Other methods go here
     * login, logout, editAccount, emailConfirmation
     * etc.
     */

    public function getUsersTable() {
        if (!$this->usersTable) {
            $sm = $this->getServiceLocator();
            $this->usersTable = $sm->get('User\Entity\UsersTable');
        }
        return $this->usersTable;
    }
}

首先,我觉得有必要在这里喊: 如果在我的/config/autoload/global.php中我设置了数据库连接,为什么我应该在应用程序的任何其他地方指定关于数据库的任何其他内容(除了可能只是我想要的表)用吗? 为什么我必须在模块级别(有时甚至在控制器中)使用setter和getter以及工厂和服务管理器等,并且如此繁重地编写代码?从各种各样的例子中我可以看到(我从Module.php中的getServiceConfig()中编写代码),我需要为每个实体做到这一点。跆拳道?这太烂了!重要时刻! 然后,如果我在控制器中使用#n表,我必须有#n函数,如"公共函数getUsersTable(){}"? #n工厂喜欢' User \ Entity \ UsersTable'在Module.php中的getServiceConfig()中?那个废话!这是最好的方式吗?或者我只是运气不好并且在学习zf2的同时继续找到最糟糕的例子?为什么我的控制器中应该有一个getTableNameTable()函数?不是那个应该担心我正在谈论的表格的模型吗?由于每个型号都是针对一个特定的表设计的?就像在zf1中一样,我只需要保护$ _name ='用户&#39 ;;"在我的模型中,这就是我所需要的。

为什么没有这些连接设置"神奇地" (简单地)在我的应用程序中可以使用任何地方,比如在zf1中?为什么我把它放在配置中呢?我真的不明白为什么我需要在Module.php的getServiceConfig()中完成所有这些操作,我怎么能避免这种情况?

zf1中的东西更加紧凑。在zf2中,大部分时间我都不知道我在做什么,我在表单提交或F5上复制snipets和猎物,他们开箱即用,我没有错误。我也应该提一下,我对OOP没有很强的理解,我只是一个想要学习zf2的新手(在使用zf1之后,对于与数据库,内容管理有很大关系的2个项目, ajax,使用facebook api,谷歌地图)。使用zf1,即使我有一个关于OOP的概念,我仍然可以做任何我需要做的事情。在zf2中,它接缝有1000种开箱即用的功能。几乎每次我都在寻找解决我遇到的一些问题的解决方案时,我会发现很多例子......但是大多数时候,没有一个例子的基本代码类似于我的构建,所以我必须重写很多(因为我无法适应,我是新手,如果我适应我发现的东西,我会立即得到错误,即使我根据我找到的示例重写,我有时会得到错误。)

所以,我要问的是:

  1. 在上面粘贴的代码中,为了对数据库进行验证,我应该添加/ modiffy?因为,现在,我得到了#34;没有数据库适配器存在" < em>确定我做了< / em>

  2. 这可能超出了本文的初始范围,但是我怎样才能避免这么多的代码和配置遍布整个地方?我不想在整个应用程序中指定任何关于数据库连接的内容,它确实应该在一个地方完成,所有其他模块和实体和控制器应该知道所有关于数据库的知识(不告诉我们)他们在每个控制器/模型中查看它们,他们应该只知道从配置中),他们在模型(实体)/控制器级别需要知道的任何其他内容应该只是我想要使用的表,我不应该&#39 ; t需要重复自己,并继续说到#34;这是我的适配器,在那里 - 从>这里得到它<" - 那个废话)停止弄乱吸气剂和制定者以及工厂和服务经理,并且#34;从那里开始使用那里的那个"我不应该在我的InputFilters或除global / local.php之外的任何地方指定适配器。我应该告诉输入过滤器中验证器的所有内容是要验证的表和列,这不是更自然吗?

1 个答案:

答案 0 :(得分:0)

我是通过将适配器传递给我的界面来完成的:

控制器代码:

    if ($request->isPost()) {
                $dbAdapter = $this->getServiceLocator()->get('Zend\Db\Adapter\Adapter');
                $admins = new Admins($dbAdapter);
.
.
.
}

我的界面代码:

class Admins implements InputFilterAwareInterface 
{
    public $id;
    public $first_name;
    public $last_name;
    /* etc */

    private $gatewayAdapter;

    public function __construct($dbAdapter = null) {
        $this->gatewayAdapter = $dbAdapter;
    }

    /* etc*/

    public function getInputFilter() {
    if (!$this->inputFilter) {
        $inputFilter = new InputFilter();
        $factory     = new InputFactory();

        $inputFilter->add($factory->createInput(array(
            'name'     => 'id',
            'required' => true,
            'filters'  => array(
                array('name' => 'Int'),
            ),
        )));
        /* etc */
        $inputFilter->add($factory->createInput(array(
            'name'     => 'email',
            'required' => true,
            'filters'  => array(
                array('name' => 'StripTags'),
                array('name' => 'StringTrim'),
            ),
            'validators' => array(
                array('name'    => 'NotEmpty',),
                array(
                    'name' => 'Db\NoRecordExists',
                    'options' => array(
                        'table' => 'admins',
                        'field' => 'email',
                        'adapter' => $this->gatewayAdapter
                    ),
                ),
            ),
        )));
            /* etc */
    }

    /* etc */

}