【问题标题】:Zend Framework 2 Db Validator Zend\Validate\Db\NoRecordExists - I just can't make things work for meZend Framework 2 Db Validator Zend\Validate\Db\NoRecordExists - 我无法让事情为我工作
【发布时间】:2014-01-03 22:26:16
【问题描述】:

我一直在搜索,找到了一些“解决方案”,有些甚至让我重写了我的大部分 InputFilter 并在我的 Module.php 和/或 module.config.php 中添加了很多东西。 ..没有任何运气......只是无法让它为我工作,仍然有各种各样的错误。 我决定撤消所有操作并从头开始(我的代码最初的样子,在针对 db 验证表单条目之前)并在这里提出我的问题。

我正在做一个注册过程。 当然,我需要根据用户表中的现有记录验证电子邮件地址(不应允许 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 函数,如“public function getUsersTable() {}”?在我的 Module.php 中的 getServiceConfig() 中还有 #n 个工厂,例如 'User\Entity\UsersTable'?那是废话!这是最好的方法吗?还是我只是不走运,在学习 zf2 时一直在寻找最糟糕的例子?为什么我的控制器中应该有一个 getTableNameTable() 函数?不是应该担心我在说什么表的模型吗?因为每个模型都是为一个特定的表设计的?就像在 zf1 中一样,我只需要“受保护的 $_name = 'users';”在我的模型中,这就是我所需要的。

为什么这些连接设置不能“神奇地”(简单地)在我的应用程序中的任何地方都可用,比如在 zf1 中?为什么我还要把它放在配置中?我真的不明白为什么我的 Module.php 中的 getServiceConfig() 需要所有这些,我该如何避免呢?

zf1 中的东西接缝更紧凑。在 zf2 中,大多数时候我对自己在做什么一无所知,我复制片段并在表单提交或 F5 上捕获它们开箱即用的工作并且我没有收到任何错误。我还应该提一下,我对 OOP 没有深入的了解,我只是一个尝试学习 zf2 的新手(在将 zf1 用于与数据库、内容管理、ajax 有很大关系的 2 个项目之后,使用facebook api,谷歌地图)。使用 zf1,即使我对 OOP 有想法,我仍然可以做任何我需要做的事情。在 zf2 中,它接缝了 1000 种开箱即用的方法来完成每一件事。几乎每次我为遇到的问题寻找解决方案时,我都会找到很多示例……但大多数时候,没有示例具有与我类似的基本代码可以构建,所以我必须重写很多(因为我不能适应,我是新手,如果我适应我发现的东西,我会立即得到错误,即使我根据我找到的示例重写有时也会出错)。

所以,我要问的是:

  1. 在上面粘贴的我的代码中,为了对数据库进行验证,我应该添加/修改什么?因为,现在,我得到“没有数据库适配器存在”我确定

  2. 这可能超出了本文的初始范围,但是我怎样才能避免如此多的代码和配置散布在各处?我不想在整个应用程序中指定有关数据库连接的任何内容,它确实应该在一个地方完成,所有其他模块和实体以及控制器都应该知道有关数据库的所有信息(不告诉他们在哪里要查看每个控制器/模型,他们应该简单地从配置中知道),他们在模型(实体)/控制器级别需要知道的任何其他内容应该只是我想要使用的表,我不需要重复我自己并到处说“这是我的适配器,那里 - 从>这里

【问题讨论】:

  • 看来你需要this。如果您有很多具有关系的表,请尝试使用 Doctrine 2。
  • 感谢 Microbe 的建议,我一定会尝试的。现在是早上 5 点半,所以我会留到以后,等我醒来的时候再说。但是我仍然希望看到推荐的方法或人们称之为最佳实践或标准的方法,或者只是“在我的情况下大多数人会写什么”,有经验的程序员如何在我的代码中编辑/添加必要的内容以验证对数据库的字段,因为...(续)
  • (续)...因为即使有时我一开始发现变化令人沮丧(仅仅是因为我来自不同的地方,或者我习惯于以不同的方式做事 - zf1),但一旦我冷静下来我仍然愿意接受这种变化,或者至少尝试去理解,因为这往往是一种进化,而不仅仅是让事情复杂化。
  • (续)...关于教义 2... 在学习任何新事物时,我会尽量远离任何第三者,直到我学会如何充分利用盒子里的东西。对不起这么多 cmets,但是对于像我这样的“小说家”来说,字数限制有点低:)

标签: database forms validation zend-framework2


【解决方案1】:

我通过将适配器传递给我的接口来做到这一点:

控制器代码:

    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 */

}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-06-27
    • 2013-03-25
    • 1970-01-01
    • 2013-01-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多