If I need to create a Validator with complicate logic which need to use registered service as DI, can I create a factory for it?

Writing Validators - laminas-validator - Laminas Docs this page demo is too simple.

I am trying to create a factory for my customed FormHashValidator, which need a formHashProcess() from BaseFuncModel I register to container via getServiceConfig()
That means I need to inject BaseFuncModel::class as dependency via its __construct() method.

But I found AbstractValidator itself have a __construct($options = null), the new custom FormHashValidator extend from AbstractValidator. If I create a factory and inject dependency from __construct(), It will overwrite the AbstractValidator’s own __construct(). I don’t know what will happend if I overwrite a built-in method.

Besides, I haven’t found a sample from website which use factory to inject dependency to a custom Validator.

I don’t know whether I can use a factory to do the DI job.

I need to validate the formHash which posted with thread data.

my formhash process function as follow:

public function formHashProcess($uid, $action = 'generate', $sence = 'post', $time = 0, $formhashValidToken = '')
    {
        if ($action == 'generate')
        {
            $formHashArr = $this->shortUrl(uniqid().(string)(time()).(string)($uid).$sence);
            $formHashStr = implode('',$formHashArr);
            $this->redisCacheApdater('discuz-form-hash-uid-'.$uid.'-'.$sence,86400,'set',$formHashStr);//设置一个key,用来验证
            return $formHashStr;
        }
        elseif ($action == 'valid' && (int)($time) && (int)($time) > time()-3600 && $formhashValidToken)
        {
            $redisToken = $this->redisCacheApdater('discuz-form-hash-uid-'.$uid.'-'.$sence,'86400','get');
            $this->redisCacheApdater('discuz-form-hash-uid-'.$uid.'-'.$sence,'86400','remove');
            if (!$redisToken) return false;
            $tokenLen = strlen($redisToken);
            $tokenA = substr($redisToken,0,$tokenLen/2);
            $tokenB = substr($redisToken,$tokenLen/2,$tokenLen/2);
            $md5str = $tokenA . '@' . 'a private key' . '@' . $tokenB . '@' . (string)($time);
            return md5($md5str) == $formhashValidToken ? true : false;
        }
        return false;
    }

In this formhash validate function there is a uid param needed, which should be acquired via AuthManager’s getIdentity() method.

I tried Callback validator, failed! because it can not get uid via context.

The only way I can expect is the custom validator on condition that I can inject dependency via facotry. But I can not find any demo or document say something about it.

To hard to move on.

solved! I finally create a factory for the customed validator. It works fine.

Care to share your code/an example repo? I am fiddling around with creating a factory for a custom validator too and I am very curious how you did it.

thanks!

Do not have a repo, I show you my codes:

the customed validator

class FormHashValidator extends AbstractValidator
{
    const FORMHASH = 'formhash';

    private $uid;
    private $baseFuncModel;
    private $time;

    protected $messageTemplates = [
        self::FORMHASH => "'%value%' formHash没通过验证",
    ];

    public function __construct(BaseFuncModel $baseFuncModel, $uid, $time, $options = null)
    {
        parent::__construct($options);
        $this->baseFuncModel = $baseFuncModel;
        $this->uid = $uid;
        $this->time = $time;
    }

    public function isValid($value)
    {
        $this->setValue($value);

        $result = $this->baseFuncModel->formHashProcess($this->uid,'valid','threadpost',$this->time,$value);
        if (!$result) $this->error(self::FORMHASH);
        return $result;
    }
}

factory for customed validator

class FormHashValidatorFactory implements FactoryInterface
{

    public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
    {
        $baseFuncModel = $container->get(BaseFuncModel::class);
        /** @var Laminas\Http\Request $request */
        $request = $container->get('Request');
        $authManager = $container->get(AuthManager::class);
        $identityArr = $authManager->getIdentity($request);
        $time = $request->getPost('time');

        return new FormHashValidator($baseFuncModel, $identityArr['uid'], $time, $options);
    }
}

then register it

public function getValidatorConfig()
    {
        return [
            'factories' => [
                Validator\FormHashValidator::class => Validator\Factory\FormHashValidatorFactory::class,
            ],
        ];
    }

Maybe there is a better way to pass post param time as context. I inject the $_post[‘time’] from factory is very low way.

1 Like