Laminas component form validator RecordExists, what's the best way to pass dbadapter into?

My entity model which strictly follow tutorial Forms and Actions - tutorials - Laminas Docs, I create a setAdapter() method to solve this problem, I don’t think it is a good way, any other better solution?

namespace Application\Model;


use Application\Model\AbstractBase\EntityBase;
use Laminas\Db\Adapter\AdapterInterface;
use Laminas\Filter\StringTrim;
use Laminas\Filter\StripTags;
use Laminas\Filter\ToInt;
use Laminas\InputFilter\InputFilter;
use Laminas\InputFilter\InputFilterAwareInterface;
use Laminas\InputFilter\InputFilterAwareTrait;
use Laminas\Validator\Db\RecordExists;
use Laminas\Validator\NotEmpty;
use Laminas\Validator\StringLength;

class ThreadMain extends EntityBase implements InputFilterAwareInterface
{
    public $id;
    public $uid;
    public $forumid;
    public $title;
    public $content;
    public $haspic;
    public $ip;
    public $valid;
    public $machine;
    public $validator;
    public $addtime;
    public $uptime;
    public $valtime;

    private $dbAdapter;

    use InputFilterAwareTrait;

    public function setAdapter(AdapterInterface $dbAdapter)
    {
        $this->dbAdapter = $dbAdapter;
    }

    public function exchangeArray(array $data)
    {
        $this->id = !empty($data['id']) ? $data['id'] : null;
        $this->uid = !empty($data['uid']) ? $data['uid'] : null;
        $this->forumid = !empty($data['forumid']) ? $data['forumid'] : null;
        $this->title = !empty($data['title']) ? $data['title'] : null;
        $this->content = !empty($data['content']) ? $data['content'] : null;
        $this->haspic = !empty($data['haspic']) ? $data['haspic'] : null;
        $this->ip = !empty($data['ip']) ? $data['ip'] : null;
        $this->valid = !empty($data['valid']) ? $data['valid'] : null;
        $this->machine = !empty($data['machine']) ? $data['machine'] : null;
        $this->validator = !empty($data['validator']) ? $data['validator'] : null;
        $this->addtime = !empty($data['addtime']) ? $data['addtime'] : null;
        $this->uptime = !empty($data['uptime']) ? $data['uptime'] : null;
        $this->valtime = !empty($data['valtime']) ? $data['valtime'] : null;
    }

    public function getArrayCopy()
    {
        return [
            'id' => $this->id,
            'uid' => $this->uid,
            'forumid' => $this->forumid,
            'title' => $this->title,
            'content' => $this->content,
            'haspic' => $this->haspic,
            'ip' => $this->ip,
            'valid' => $this->valid,
            'machine' => $this->machine,
            'validator' => $this->validator,
            'addtime' => $this->addtime,
            'uptime' => $this->uptime,
            'valtime' => $this->valtime,
        ];
    }

    public function getInputFilter()
    {
        if ($this->inputFilter) return $this->inputFilter;

        $inputFilter = new InputFilter();

        $inputFilter->add([
            'name' => 'id',
            'required' => true,
            'filters' => [
                ['name' => ToInt::class],
            ],
        ]);

        $inputFilter->add([
            'name' => 'uid',
            'required' => true,
            'filters' => [
                ['name' => ToInt::class],
            ],
            'validators' => [
                [
                    'name' => NotEmpty::class,
                    'options' => ['message' => 'uid不能为空'],
                ],
                [
                    'name' => RecordExists::class,
                    'options' => [
                        'table' => 'forum_user',
                        'field' => 'uid',
                        'adapter' => $this->dbAdapter,
                        'message' => 'uid不存在',
                    ],
                ],
            ],
        ]);

        $inputFilter->add([
            'name' => 'forumid',
            'required' => true,
            'filters' => [
                ['name' => ToInt::class],
            ],
            'validators' => [
                [
                    'name' => NotEmpty::class,
                    'options' => ['message' => 'forumid不能为空'],
                ],
                [
                    'name' => RecordExists::class,
                    'options' => [
                        'table' => 'forum_main',
                        'field' => 'id',
                        'adapter' => $this->dbAdapter,
                        'message' => 'forumid不存在',
                    ],
                ],
            ],
        ]);

        $inputFilter->add([
            'name' => 'title',
            'required' => true,
            'filters' => [
                ['name' => StripTags::class],
                ['name' => StringTrim::class],
            ],
            'validators' => [
                [
                    'name' => StringLength::class,
                    'options' => [
                        'encoding' => 'UTF-8',
                        'min' => 1,
                        'max' => 100, //先写100试下
                        'message' => '长度1-100',
                    ],
                ],
            ],
        ]);

        $inputFilter->add([
            'name' => 'content',
            'required' => true,
            'filters' => [
                ['name' => StringTrim::class],
            ],
            'validators' => [
                [
                    'name' => StringLength::class,
                    'options' => [
                        'encoding' => 'UTF-8',
                        'min' => 1,
                        'max' => 1000, //先写1000试下
                        'message' => '长度1-1000',
                    ],
                ],
            ],
        ]);

        $this->inputFilter = $inputFilter;
        return $this->inputFilter;
    }

I just found a topic I raised before About zf3 validator of RecordExists - #11 by froschdesign

It seems I didn’t solved it yet.

Set the database adapter to the validator directly. This can be done via the delegator from laminas-db.

Add the following to your global application configuration (e.g. config/autoload/global.config.php):

return [
    'validators' => [
        'delegators' => [
            Laminas\Validator\Db\RecordExists::class => [
                Laminas\Db\Adapter\AdapterServiceDelegator::class,
            ],
        ],
    ],
];

Laminas\Validator\Db\RecordExists or Laminas\Validator\Db\RecordExists::class ?

I ordinary seem there is a ::class as a typehint, I don’t known whether there need a ::class

I corrected my example but you should know for yourself how to do it right! :wink:

Ok, I followed your suggestion and I am testing my code.

I config it in my autoload/global.php

'validators' => [
        'delegators' => [
            Laminas\Validator\Db\RecordExists::class => [
                Laminas\Db\Adapter\AdapterServiceDelegator::class,
            ],
        ],
    ],

In my entity model which implements InputFilterAwareInterface

$inputFilter->add([
            'name' => 'forumid',
            'required' => true,
            'filters' => [
                ['name' => ToInt::class],
            ],
            'validators' => [
                [
                    'name' => NotEmpty::class,
                    'options' => ['message' => 'forumid不能为空'],
                ],
                [
                    'name' => RecordExists::class,
                    'options' => [
                        'table' => 'forum_main',
                        'field' => 'id',
                        //'adapter' => $this->dbAdapter,
                        'message' => 'forumid不存在',
                    ],
                ],
            ],
        ]);

Now it raise error with message:

If I changed it into

$inputFilter->add([
            'name' => 'forumid',
            'required' => true,
            'filters' => [
                ['name' => ToInt::class],
            ],
            'validators' => [
                [
                    'name' => NotEmpty::class,
                    'options' => ['message' => 'forumid不能为空'],
                ],
                [
                    'name' => RecordExists::class,
                    'options' => [
                        'table' => 'forum_main',
                        'field' => 'id',
                        'adapter' => AdapterInterface::class,
                        'message' => 'forumid不存在',
                    ],
                ],
            ],
        ]);

then the error changed into:

Still not work when I use AdapterAwareTrait

namespace Application\Model;


use Application\Model\AbstractBase\EntityBase;
use Laminas\Db\Adapter\AdapterAwareTrait;
use Laminas\Db\Adapter\AdapterInterface;
use Laminas\Filter\StringTrim;
use Laminas\Filter\StripTags;
use Laminas\Filter\ToInt;
use Laminas\InputFilter\InputFilter;
use Laminas\InputFilter\InputFilterAwareInterface;
use Laminas\InputFilter\InputFilterAwareTrait;
use Laminas\Validator\Db\RecordExists;
use Laminas\Validator\NotEmpty;
use Laminas\Validator\StringLength;

class ThreadMain extends EntityBase implements InputFilterAwareInterface
{
    public $id;
    public $uid;
    public $forumid;
    public $title;
    public $content;
    public $haspic;
    public $ip;
    public $valid;
    public $machine;
    public $validator;
    public $addtime;
    public $uptime;
    public $valtime;

    private $dbAdapter;

    use InputFilterAwareTrait;
    use AdapterAwareTrait;

    public function setAdapter(AdapterInterface $dbAdapter)
    {
        $this->dbAdapter = $dbAdapter;
    }

    public function exchangeArray(array $data)
    {
        $this->id = !empty($data['id']) ? $data['id'] : null;
        $this->uid = !empty($data['uid']) ? $data['uid'] : null;
        $this->forumid = !empty($data['forumid']) ? $data['forumid'] : null;
        $this->title = !empty($data['title']) ? $data['title'] : null;
        $this->content = !empty($data['content']) ? $data['content'] : null;
        $this->haspic = !empty($data['haspic']) ? $data['haspic'] : null;
        $this->ip = !empty($data['ip']) ? $data['ip'] : null;
        $this->valid = !empty($data['valid']) ? $data['valid'] : null;
        $this->machine = !empty($data['machine']) ? $data['machine'] : null;
        $this->validator = !empty($data['validator']) ? $data['validator'] : null;
        $this->addtime = !empty($data['addtime']) ? $data['addtime'] : null;
        $this->uptime = !empty($data['uptime']) ? $data['uptime'] : null;
        $this->valtime = !empty($data['valtime']) ? $data['valtime'] : null;
    }

    public function getArrayCopy()
    {
        return [
            'id' => $this->id,
            'uid' => $this->uid,
            'forumid' => $this->forumid,
            'title' => $this->title,
            'content' => $this->content,
            'haspic' => $this->haspic,
            'ip' => $this->ip,
            'valid' => $this->valid,
            'machine' => $this->machine,
            'validator' => $this->validator,
            'addtime' => $this->addtime,
            'uptime' => $this->uptime,
            'valtime' => $this->valtime,
        ];
    }

    public function getInputFilter()
    {
        if ($this->inputFilter) return $this->inputFilter;

        $inputFilter = new InputFilter();

        $inputFilter->add([
            'name' => 'id',
            'required' => true,
            'filters' => [
                ['name' => ToInt::class],
            ],
        ]);

        $inputFilter->add([
            'name' => 'uid',
            'required' => true,
            'filters' => [
                ['name' => ToInt::class],
            ],
            'validators' => [
                [
                    'name' => NotEmpty::class,
                    'options' => ['message' => 'uid不能为空'],
                ],
                [
                    'name' => RecordExists::class,
                    'options' => [
                        'table' => 'forum_user',
                        'field' => 'uid',
                        'adapter' => $this->adapter,
                        'message' => 'uid不存在',
                    ],
                ],
            ],
        ]);

        $inputFilter->add([
            'name' => 'forumid',
            'required' => true,
            'filters' => [
                ['name' => ToInt::class],
            ],
            'validators' => [
                [
                    'name' => NotEmpty::class,
                    'options' => ['message' => 'forumid不能为空'],
                ],
                [
                    'name' => RecordExists::class,
                    'options' => [
                        'table' => 'forum_main',
                        'field' => 'id',
                        'adapter' => $this->adapter,
                        'message' => 'forumid不存在',
                    ],
                ],
            ],
        ]);

        $inputFilter->add([
            'name' => 'title',
            'required' => true,
            'filters' => [
                ['name' => StripTags::class],
                ['name' => StringTrim::class],
            ],
            'validators' => [
                [
                    'name' => StringLength::class,
                    'options' => [
                        'encoding' => 'UTF-8',
                        'min' => 1,
                        'max' => 100, //先写100试下
                        'message' => '长度1-100',
                    ],
                ],
            ],
        ]);

        $inputFilter->add([
            'name' => 'content',
            'required' => true,
            'filters' => [
                ['name' => StringTrim::class],
            ],
            'validators' => [
                [
                    'name' => StringLength::class,
                    'options' => [
                        'encoding' => 'UTF-8',
                        'min' => 1,
                        'max' => 1000, //先写1000试下
                        'message' => '长度1-1000',
                    ],
                ],
            ],
        ]);

        $this->inputFilter = $inputFilter;
        return $this->inputFilter;
    }
}

Please don’t guess!


The problem is here:

You create an input filter which is decoupled from your application, so it can not use any other registered service from your application, including the database adapter.
Yes it is described in the getting start tutorial but not a good direction. It leads to problems with own filters, validators or any other dependencies.

Since the input filter is only used in the form, it should not added to the entity. Move the input filter to the form. An example can be found in the documentation of laminas-form.

And decoupled from your application means also that you do not create a form via:
new MyForm().

Ah, I need to learn more.

Yes, I do have a ThreadMainForm.php, which looks like:

namespace Application\Form;


use Laminas\Form\Element\Hidden;
use Laminas\Form\Form;

class ThreadMainForm extends Form
{
    public function __construct($name = null, $options = [])
    {
        parent::__construct($name, $options);

        $this->add([
            'name' => 'id',
            'type' => Hidden::class,
        ]);

        $this->add([
            'name' => 'uid',
            'type' => Hidden::class,
        ]);

        $this->add([
            'name' => 'forumid',
            'type' => Hidden::class,
        ]);

        $this->add([
            'name' => 'title',
            'type' => Hidden::class,
        ]);

        $this->add([
            'name' => 'content',
            'type' => Hidden::class,
        ]);
    }
}

In fact, I don’t need a view and don’t need to render the form, because the app(for andorid and ios) will submit the data.

I tried to write my own validator called FormHashValidator, in which I need to use logic from other model which I register in service manager.
I wanna to build a factory for the custom validator, but I found It exends the AbstractValidator which have a __construct() and accept some options parameter.
I am not sure, the factory inject dependency is the correct way. Becuase it will overwrite the __construct() of AbstractValidator

namespace Application\Validator;


use Laminas\Validator\AbstractValidator;
use Laminas\Validator\Exception;

class FormHashValidator extends AbstractValidator
{

    public function isValid($value)
    {
        // TODO: Implement isValid() method.
    }
}

Add the input filter here like in example from the documentation.

Ok, I am trying… hope it will go smoothly.

I found It changed a lot:

My Form:

use Laminas\Filter\StringTrim;
use Laminas\Filter\StripTags;
use Laminas\Filter\ToInt;
use Laminas\Form\Element\Hidden;
use Laminas\Form\Form;
use Laminas\InputFilter\InputFilterProviderInterface;
use Laminas\Validator\Db\RecordExists;
use Laminas\Validator\NotEmpty;
use Laminas\Validator\StringLength;

class ThreadMainForm extends Form implements InputFilterProviderInterface
{
    public function init() : void
    {
        $this->add([
            'name' => 'id',
            'type' => Hidden::class,
        ]);

        $this->add([
            'name' => 'uid',
            'type' => Hidden::class,
        ]);

        $this->add([
            'name' => 'forumid',
            'type' => Hidden::class,
        ]);

        $this->add([
            'name' => 'title',
            'type' => Hidden::class,
        ]);

        $this->add([
            'name' => 'content',
            'type' => Hidden::class,
        ]);
    }

    public function getInputFilterSpecification() : array
    {
        return [
            [
                'name' => 'id',
                'required' => true,
                'filters' => [
                    ['name' => ToInt::class],
                ],
            ],
            [
                'name' => 'uid',
                'required' => true,
                'filters' => [
                    ['name' => ToInt::class],
                ],
                'validators' => [
                    [
                        'name' => NotEmpty::class,
                        'options' => ['message' => 'uid不能为空'],
                    ],
                    [
                        'name' => RecordExists::class,
                        'options' => [
                            'table' => 'forum_user',
                            'field' => 'uid',
                            //'adapter' => $this->dbAdapter,
                            'message' => 'uid不存在',
                        ],
                    ],
                ],
            ],
            [
                'name' => 'forumid',
                'required' => true,
                'filters' => [
                    ['name' => ToInt::class],
                ],
                'validators' => [
                    [
                        'name' => NotEmpty::class,
                        'options' => ['message' => 'forumid不能为空'],
                    ],
                    [
                        'name' => RecordExists::class,
                        'options' => [
                            'table' => 'forum_main',
                            'field' => 'id',
                            //'adapter' => $this->dbAdapter,
                            'message' => 'forumid不存在',
                        ],
                    ],
                ],
            ],
            [
                'name' => 'title',
                'required' => true,
                'filters' => [
                    ['name' => StripTags::class],
                    ['name' => StringTrim::class],
                ],
                'validators' => [
                    [
                        'name' => StringLength::class,
                        'options' => [
                            'encoding' => 'UTF-8',
                            'min' => 1,
                            'max' => 100, //先写100试下
                            'message' => '长度1-100',
                        ],
                    ],
                ],
            ],
            [
                'name' => 'content',
                'required' => true,
                'filters' => [
                    ['name' => StringTrim::class],
                ],
                'validators' => [
                    [
                        'name' => StringLength::class,
                        'options' => [
                            'encoding' => 'UTF-8',
                            'min' => 1,
                            'max' => 1000, //先写1000试下
                            'message' => '长度1-1000',
                        ],
                    ],
                ],
            ]
        ];
    }
}

And my entity, I mius a lot, now it is:

use Application\Model\AbstractBase\EntityBase;

class ThreadMain extends EntityBase
{
    public $id;
    public $uid;
    public $forumid;
    public $title;
    public $content;
    public $haspic;
    public $ip;
    public $valid;
    public $machine;
    public $validator;
    public $addtime;
    public $uptime;
    public $valtime;

    public function exchangeArray(array $data)
    {
        $this->id = !empty($data['id']) ? $data['id'] : null;
        $this->uid = !empty($data['uid']) ? $data['uid'] : null;
        $this->forumid = !empty($data['forumid']) ? $data['forumid'] : null;
        $this->title = !empty($data['title']) ? $data['title'] : null;
        $this->content = !empty($data['content']) ? $data['content'] : null;
        $this->haspic = !empty($data['haspic']) ? $data['haspic'] : null;
        $this->ip = !empty($data['ip']) ? $data['ip'] : null;
        $this->valid = !empty($data['valid']) ? $data['valid'] : null;
        $this->machine = !empty($data['machine']) ? $data['machine'] : null;
        $this->validator = !empty($data['validator']) ? $data['validator'] : null;
        $this->addtime = !empty($data['addtime']) ? $data['addtime'] : null;
        $this->uptime = !empty($data['uptime']) ? $data['uptime'] : null;
        $this->valtime = !empty($data['valtime']) ? $data['valtime'] : null;
    }

    public function getArrayCopy()
    {
        return [
            'id' => $this->id,
            'uid' => $this->uid,
            'forumid' => $this->forumid,
            'title' => $this->title,
            'content' => $this->content,
            'haspic' => $this->haspic,
            'ip' => $this->ip,
            'valid' => $this->valid,
            'machine' => $this->machine,
            'validator' => $this->validator,
            'addtime' => $this->addtime,
            'uptime' => $this->uptime,
            'valtime' => $this->valtime,
        ];
    }
}

But I don’t know what to do with my controller action, I didn’t create a single factory for it, and I used LazyControllerAbstractFactory::class

The example from the documentation ask me to create a controllerfactory special for it. I can not move at this part. Usage in a laminas-mvc application - laminas-form - Laminas Docs

My action:

public function threadmainpostAction()
    {
        $identityArr = $this->plugin('auth')->getIdentity($this->getRequest());

        $form = new ThreadMainForm();

        $request = $this->getRequest();

        if (!$request->isPost()) return new JsonModel([
            'status' => false,
            'msg' => 'post方式提交',
            'code' => 111,
            'data' => null,
        ]);

        $threadMain = new ThreadMain();
        $form->setValidationGroup('forumid','title','content');
        $form->setInputFilter($threadMain->getInputFilter());
        $form->setData($request->getPost());

        if (!$form->isValid()) return new JsonModel([
            'status' => false,
            'msg' => '数据审核不通过',
            'code' => 111,
            'data' => null,
        ]);

        //formHash单独验证

        $threadMain->exchangeArray($form->getData());
        $result = $this->threadMainTable->saveRecord($threadMain,$request,$this->baseFuncModel,$identityArr);

        return new JsonModel([
            'status' => $result ? true : false,
            'msg' => $result ? '发帖成功' : '发帖失败',
            'code' => 111,
            'data' => null,
        ]);
    }

Still not work, and got error message:

My code now:

  1. autoload/global.php
'validators' => [
        'delegators' => [
            Laminas\Validator\Db\RecordExists::class => [
                Laminas\Db\Adapter\AdapterServiceDelegator::class,
            ],
        ],
    ],
  1. entity ThreadMain.php
namespace Application\Model;


use Application\Model\AbstractBase\EntityBase;

class ThreadMain extends EntityBase
{
    public $id;
    public $uid;
    public $forumid;
    public $title;
    public $content;
    public $haspic;
    public $ip;
    public $valid;
    public $machine;
    public $validator;
    public $addtime;
    public $uptime;
    public $valtime;

    public function exchangeArray(array $data)
    {
        $this->id = !empty($data['id']) ? $data['id'] : null;
        $this->uid = !empty($data['uid']) ? $data['uid'] : null;
        $this->forumid = !empty($data['forumid']) ? $data['forumid'] : null;
        $this->title = !empty($data['title']) ? $data['title'] : null;
        $this->content = !empty($data['content']) ? $data['content'] : null;
        $this->haspic = !empty($data['haspic']) ? $data['haspic'] : null;
        $this->ip = !empty($data['ip']) ? $data['ip'] : null;
        $this->valid = !empty($data['valid']) ? $data['valid'] : null;
        $this->machine = !empty($data['machine']) ? $data['machine'] : null;
        $this->validator = !empty($data['validator']) ? $data['validator'] : null;
        $this->addtime = !empty($data['addtime']) ? $data['addtime'] : null;
        $this->uptime = !empty($data['uptime']) ? $data['uptime'] : null;
        $this->valtime = !empty($data['valtime']) ? $data['valtime'] : null;
    }

    public function getArrayCopy()
    {
        return [
            'id' => $this->id,
            'uid' => $this->uid,
            'forumid' => $this->forumid,
            'title' => $this->title,
            'content' => $this->content,
            'haspic' => $this->haspic,
            'ip' => $this->ip,
            'valid' => $this->valid,
            'machine' => $this->machine,
            'validator' => $this->validator,
            'addtime' => $this->addtime,
            'uptime' => $this->uptime,
            'valtime' => $this->valtime,
        ];
    }
}
  1. ThreadMainForm.php
namespace Application\Form;


use Laminas\Db\Adapter\Adapter;
use Laminas\Db\Adapter\AdapterAwareInterface;
use Laminas\Db\Adapter\AdapterAwareTrait;
use Laminas\Filter\StringTrim;
use Laminas\Filter\StripTags;
use Laminas\Filter\ToInt;
use Laminas\Form\Element\Hidden;
use Laminas\Form\Form;
use Laminas\InputFilter\InputFilterProviderInterface;
use Laminas\Validator\Db\RecordExists;
use Laminas\Validator\NotEmpty;
use Laminas\Validator\StringLength;

class ThreadMainForm extends Form implements InputFilterProviderInterface, AdapterAwareInterface
{
    use AdapterAwareTrait;

    public function getAdapter() : ?Adapter
    {
        return $this->adapter;
    }

    public function init() : void
    {
        $this->add([
            'name' => 'id',
            'type' => Hidden::class,
        ]);

        $this->add([
            'name' => 'uid',
            'type' => Hidden::class,
        ]);

        $this->add([
            'name' => 'forumid',
            'type' => Hidden::class,
        ]);

        $this->add([
            'name' => 'title',
            'type' => Hidden::class,
        ]);

        $this->add([
            'name' => 'content',
            'type' => Hidden::class,
        ]);
    }

    public function getInputFilterSpecification() : array
    {
        return [
            [
                'name' => 'id',
                'required' => true,
                'filters' => [
                    ['name' => ToInt::class],
                ],
            ],
            [
                'name' => 'uid',
                'required' => true,
                'filters' => [
                    ['name' => ToInt::class],
                ],
                'validators' => [
                    [
                        'name' => NotEmpty::class,
                        'options' => ['message' => 'uid不能为空'],
                    ],
                    [
                        'name' => RecordExists::class,
                        'options' => [
                            'table' => 'forum_user',
                            'field' => 'uid',
                            'adapter' => $this->adapter,
                            'message' => 'uid不存在',
                        ],
                    ],
                ],
            ],
            [
                'name' => 'forumid',
                'required' => true,
                'filters' => [
                    ['name' => ToInt::class],
                ],
                'validators' => [
                    [
                        'name' => NotEmpty::class,
                        'options' => ['message' => 'forumid不能为空'],
                    ],
                    [
                        'name' => RecordExists::class,
                        'options' => [
                            'table' => 'forum_main',
                            'field' => 'id',
                            'adapter' => $this->adapter,
                            'message' => 'forumid不存在',
                        ],
                    ],
                ],
            ],
            [
                'name' => 'title',
                'required' => true,
                'filters' => [
                    ['name' => StripTags::class],
                    ['name' => StringTrim::class],
                ],
                'validators' => [
                    [
                        'name' => StringLength::class,
                        'options' => [
                            'encoding' => 'UTF-8',
                            'min' => 1,
                            'max' => 100, //先写100试下
                            'message' => '长度1-100',
                        ],
                    ],
                ],
            ],
            [
                'name' => 'content',
                'required' => true,
                'filters' => [
                    ['name' => StringTrim::class],
                ],
                'validators' => [
                    [
                        'name' => StringLength::class,
                        'options' => [
                            'encoding' => 'UTF-8',
                            'min' => 1,
                            'max' => 1000, //先写1000试下
                            'message' => '长度1-1000',
                        ],
                    ],
                ],
            ]
        ];
    }
}
  1. controller action
/** 最好还是接入之前做好的传图的功能,授权写到 filterAccess,如果 */
    public function threadmainpostAction()
    {
        $request = $this->getRequest();

        $identityArr = $this->plugin('auth')->getIdentity($request);

        $form = new ThreadMainForm();

        if (!$request->isPost()) return new JsonModel([
            'status' => false,
            'msg' => 'post方式提交',
            'code' => 111,
            'data' => null,
        ]);

        $form->setValidationGroup('forumid','title','content');
        $form->setData($request->getPost());

        if (!$form->isValid()) return new JsonModel([
            'status' => false,
            'msg' => '数据审核不通过',
            'code' => 111,
            'data' => null,
        ]);

        //formHash单独验证

        $threadMain = new ThreadMain();
        $threadMain->exchangeArray($form->getData());
        $result = $this->threadMainTable->saveRecord($threadMain,$request,$this->baseFuncModel,$identityArr);

        return new JsonModel([
            'status' => $result ? true : false,
            'msg' => $result ? '发帖成功' : '发帖失败',
            'code' => 111,
            'data' => null,
        ]);
    }

not work, I don’t know why :frowning:

The same as before:

This form is also decoupled from your application, the form is created separately and can not use any registered service of your application.

But this can be solved with the form element manager from laminas-form.

Extend the constructor of your controller and use form element manager to get the form, like this:

namespace MyModule\Controller;

use Laminas\Form\FormElementManager;
use Laminas\Mvc\Controller\AbstractActionController;

class MyController extends AbstractActionController
{
    private FormElementManager $formElementManager;

    public function __construct(FormElementManager $formElementManager)
    {
        $this->formElementManager = $formElementManager;
    }

    public function threadmainpostAction()
    {
        $form = $this->formElementManager->get(ThreadMainForm::class);
        // …
    }
}

The factory LazyControllerAbstractFactory works also here and the form element manager is injected.

I changed the action part to:

public function threadmainpostAction()
    {
        $request = $this->getRequest();
        $identityArr = $this->plugin('auth')->getIdentity($request);

        if (!$request->isPost()) return new JsonModel([
            'status' => false,
            'msg' => 'post方式提交',
            'code' => 111,
            'data' => null,
        ]);

        $form = $this->formElementManager->get(ThreadMainForm::class);

        $form->setValidationGroup('forumid','title','content');
        $form->setData($request->getPost());

        if (!$form->isValid()) return new JsonModel([
            'status' => false,
            'msg' => '数据审核不通过',
            'code' => 111,
            'data' => null,
        ]);

        $threadMain = new ThreadMain();
        $threadMain->exchangeArray($form->getData());
        $result = $this->threadMainTable->saveRecord($threadMain,$request,$this->baseFuncModel,$identityArr);

        return new JsonModel([
            'status' => $result ? true : false,
            'msg' => $result ? '发帖成功' : '发帖失败',
            'code' => 111,
            'data' => null,
        ]);
    }

still got error:

Is this correct:

namespace Application\Form;


use Laminas\Db\Adapter\Adapter;
use Laminas\Db\Adapter\AdapterAwareInterface;
use Laminas\Db\Adapter\AdapterAwareTrait;
use Laminas\Filter\StringTrim;
use Laminas\Filter\StripTags;
use Laminas\Filter\ToInt;
use Laminas\Form\Element\Hidden;
use Laminas\Form\Form;
use Laminas\InputFilter\InputFilterProviderInterface;
use Laminas\Validator\Db\RecordExists;
use Laminas\Validator\NotEmpty;
use Laminas\Validator\StringLength;

class ThreadMainForm extends Form implements InputFilterProviderInterface, AdapterAwareInterface
{
    use AdapterAwareTrait;

    public function getAdapter() : ?Adapter
    {
        return $this->adapter;
    }

    public function init() : void
    {
        $this->add([
            'name' => 'id',
            'type' => Hidden::class,
        ]);

        $this->add([
            'name' => 'uid',
            'type' => Hidden::class,
        ]);

        $this->add([
            'name' => 'forumid',
            'type' => Hidden::class,
        ]);

        $this->add([
            'name' => 'title',
            'type' => Hidden::class,
        ]);

        $this->add([
            'name' => 'content',
            'type' => Hidden::class,
        ]);
    }

    public function getInputFilterSpecification() : array
    {
        return [
            [
                'name' => 'id',
                'required' => true,
                'filters' => [
                    ['name' => ToInt::class],
                ],
            ],
            [
                'name' => 'uid',
                'required' => true,
                'filters' => [
                    ['name' => ToInt::class],
                ],
                'validators' => [
                    [
                        'name' => NotEmpty::class,
                        'options' => ['message' => 'uid不能为空'],
                    ],
                    [
                        'name' => RecordExists::class,
                        'options' => [
                            'table' => 'forum_user',
                            'field' => 'uid',
                            'adapter' => $this->adapter,
                            'message' => 'uid不存在',
                        ],
                    ],
                ],
            ],
            [
                'name' => 'forumid',
                'required' => true,
                'filters' => [
                    ['name' => ToInt::class],
                ],
                'validators' => [
                    [
                        'name' => NotEmpty::class,
                        'options' => ['message' => 'forumid不能为空'],
                    ],
                    [
                        'name' => RecordExists::class,
                        'options' => [
                            'table' => 'forum_main',
                            'field' => 'id',
                            'adapter' => $this->adapter,
                            'message' => 'forumid不存在',
                        ],
                    ],
                ],
            ],
            [
                'name' => 'title',
                'required' => true,
                'filters' => [
                    ['name' => StripTags::class],
                    ['name' => StringTrim::class],
                ],
                'validators' => [
                    [
                        'name' => StringLength::class,
                        'options' => [
                            'encoding' => 'UTF-8',
                            'min' => 1,
                            'max' => 100, //先写100试下
                            'message' => '长度1-100',
                        ],
                    ],
                ],
            ],
            [
                'name' => 'content',
                'required' => true,
                'filters' => [
                    ['name' => StringTrim::class],
                ],
                'validators' => [
                    [
                        'name' => StringLength::class,
                        'options' => [
                            'encoding' => 'UTF-8',
                            'min' => 1,
                            'max' => 1000, //先写1000试下
                            'message' => '长度1-1000',
                        ],
                    ],
                ],
            ]
        ];
    }
}

Your form is wrong.

Remove this

And update your input filter:

The database adapter is set to the validator not to your form or to an input filter. There is no magic, please look at the following code, there is the validator and delegator which sets the database adapter to the validator:

return [
    'validators' => [
        'delegators' => [
            Laminas\Validator\Db\RecordExists::class => [
                Laminas\Db\Adapter\AdapterServiceDelegator::class,
            ],
        ],
    ],
];

still wrong:

My Form:

namespace Application\Form;


use Laminas\Filter\StringTrim;
use Laminas\Filter\StripTags;
use Laminas\Filter\ToInt;
use Laminas\Form\Element\Hidden;
use Laminas\Form\Form;
use Laminas\InputFilter\InputFilterProviderInterface;
use Laminas\Validator\Db\RecordExists;
use Laminas\Validator\NotEmpty;
use Laminas\Validator\StringLength;

class ThreadMainForm extends Form implements InputFilterProviderInterface
{
    public function init() : void
    {
        $this->add([
            'name' => 'id',
            'type' => Hidden::class,
        ]);

        $this->add([
            'name' => 'uid',
            'type' => Hidden::class,
        ]);

        $this->add([
            'name' => 'forumid',
            'type' => Hidden::class,
        ]);

        $this->add([
            'name' => 'title',
            'type' => Hidden::class,
        ]);

        $this->add([
            'name' => 'content',
            'type' => Hidden::class,
        ]);
    }

    public function getInputFilterSpecification() : array
    {
        return [
            [
                'name' => 'id',
                'required' => true,
                'filters' => [
                    ['name' => ToInt::class],
                ],
            ],
            [
                'name' => 'uid',
                'required' => true,
                'filters' => [
                    ['name' => ToInt::class],
                ],
                'validators' => [
                    [
                        'name' => NotEmpty::class,
                        'options' => ['message' => 'uid不能为空'],
                    ],
                    [
                        'name' => RecordExists::class,
                        'options' => [
                            'table' => 'forum_user',
                            'field' => 'uid',
                            //'adapter' => $this->adapter,
                            'message' => 'uid不存在',
                        ],
                    ],
                ],
            ],
            [
                'name' => 'forumid',
                'required' => true,
                'filters' => [
                    ['name' => ToInt::class],
                ],
                'validators' => [
                    [
                        'name' => NotEmpty::class,
                        'options' => ['message' => 'forumid不能为空'],
                    ],
                    [
                        'name' => RecordExists::class,
                        'options' => [
                            'table' => 'forum_main',
                            'field' => 'id',
                            'message' => 'forumid不存在',
                        ],
                    ],
                ],
            ],
            [
                'name' => 'title',
                'required' => true,
                'filters' => [
                    ['name' => StripTags::class],
                    ['name' => StringTrim::class],
                ],
                'validators' => [
                    [
                        'name' => StringLength::class,
                        'options' => [
                            'encoding' => 'UTF-8',
                            'min' => 1,
                            'max' => 100, //先写100试下
                            'message' => '长度1-100',
                        ],
                    ],
                ],
            ],
            [
                'name' => 'content',
                'required' => true,
                'filters' => [
                    ['name' => StringTrim::class],
                ],
                'validators' => [
                    [
                        'name' => StringLength::class,
                        'options' => [
                            'encoding' => 'UTF-8',
                            'min' => 1,
                            'max' => 1000, //先写1000试下
                            'message' => '长度1-1000',
                        ],
                    ],
                ],
            ]
        ];
    }
}

autoload/global.php

return [
    'db' => [
        'driver' => 'Pdo',
        'dsn'    => 'mysql:dbname=discourse;host=localhost;charset=utf8mb4',
    ],
    'validators' => [
        'delegators' => [
            Laminas\Validator\Db\RecordExists::class => Laminas\Db\Adapter\AdapterServiceDelegator::class,
        ],
    ],
];

error got:

Right, because the config is wrong. Please compare my example:

return [
    'validators' => [
        'delegators' => [
            Laminas\Validator\Db\RecordExists::class => [
                Laminas\Db\Adapter\AdapterServiceDelegator::class,
            ],
        ],
    ],
];

And your config for the validators:

return [
    // …
    'validators' => [
        'delegators' => [
            Laminas\Validator\Db\RecordExists::class => Laminas\Db\Adapter\AdapterServiceDelegator::class,
        ],
    ],
];

You can set more then one delegator therefore you must use an array.

still wrong:

autoload/global.php

return [
    'db' => [
        'driver' => 'Pdo',
        'dsn'    => 'mysql:dbname=discourse;host=localhost;charset=utf8mb4',
    ],
    'validators' => [
        'delegators' => [
            Laminas\Validator\Db\RecordExists::class => [
                Laminas\Db\Adapter\AdapterServiceDelegator::class,
            ],
        ],
    ],
];

I just copy your code and paste to there.

Please check the configuration file for the module manager config/modules.config.php. The following modules must be included:

  • Laminas\Db
  • Laminas\Validator

config/modules.config.php

return [
    'Laminas\Mvc\Plugin\FilePrg',
    'Laminas\Mvc\Plugin\FlashMessenger',
    'Laminas\Mvc\Plugin\Identity',
    'Laminas\Mvc\Plugin\Prg',
    'Laminas\Session',
    'Laminas\Mvc\Middleware',
    'Laminas\Form',
    'Laminas\I18n',
    'Laminas\Log',
    'Laminas\InputFilter',
    'Laminas\Filter',
    'Laminas\Hydrator',
    'Laminas\Di',
    'Laminas\Db',
    'Laminas\Cache',
    'Laminas\Router',
    'Laminas\Validator',
    'Application',
];

The two modules you mentioned already in.