Question

I would like to get ServiceLocator in my validation class. I tried get it from Controller instance but it returns null.

MyValidation.php  
namespace Register\Validator;

use Zend\Validator\AbstractValidator;
use Register\Controller\RegisterController;

class MyValidation extends AbstractValidator {

    /*
    code...
    */

    function isValid($value)
    {
        $controller = new RegisterController();
        $sm = $controller->getServiceLocator();
        $tableGateway = $sm->get('Register\Model\RegisterTable');
        $tableGateway->myValidationMethod($value);

    }

}

Module.php

public function getServiceConfig()
{
    return array(
        'factories' => array(
            'Register\Model\RegisterTable' =>  function($sm) {
                $tableGateway = $sm->get('RegisterTableGateway');
                $table = new RegisterTable($tableGateway);
                return $table;
            },
            'RegisterTableGateway' => function ($sm) {
                $dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
                $resultSetPrototype = new ResultSet();
                $resultSetPrototype->setArrayObjectPrototype(new RegisterUser());
                return new TableGateway('table-name', $dbAdapter, null, $resultSetPrototype);
            },
        ),
    );
}

But I get Fatal error: Call to a member function get() on a non-object
What is a proper way to get ServiceLocator in model class?

Was it helpful?

Solution

You should inject the dependencies of the validator into the validator. You could do that through the options array when you assign the validator to a form field. I wrote up some sample code to demonstrate what I mean:

Register\Validator\MyValidation:

<?php
namespace Application\Validator;

use Zend\Validator\AbstractValidator;

class MyValidation extends AbstractValidator
{
    protected $tableGateway;

    public function __construct($options = null)
    {
        parent::__constructor($options);
        if ($options && is_array($options) && array_key_exists('tableGateway', $options))
        {
            $this->tableGateway = $options['tableGateway'];
        }           
    }

    public function isValid($value)
    {
        // ...
    }
}

As for the form you can either implement the ServiceLocatorAwareInterface, so it gets automatically injected with the service locator, or else inject specific dependencies into the form using a factory for the form.

Here's how you would do it using the ServiceLocatorAwareInterface:

Register\Form\MyForm:

<?php
namespace Register\Form;

use Zend\Form\Form;
use Zend\InputFilter\InputFilterProviderInterface;
use Zend\ServiceManager\ServiceLocatorAwareInterface;

class MyForm extends Form implements InputFilterProviderInterface, ServiceLocatorAwareInterface
{
    protected $servicelocator;

    public function __construct()
    {
        $this->add(array(
                'name' => 'myfield',
                'attributes' => array(
                        'type' => 'text',
                ),
                'options' => array(
                        'label' => 'Field 1'
                ),
            )
        );  
    }

    public function setServiceLocator(ServiceLocatorInterface $serviceLocator)
    {
        $this->servicelocator = $serviceLocator;
    }

    public function getServiceLocator()
    {
        return $this->servicelocator;
    }

    public function getInputFilterSpecification()
    {
        return array(
            'myfield' => array(
                'required'    => true,
                'filters'     => array(),
                'validators'  => array(
                        array(
                            'name'    => 'Application\Validator\MyValidator',
                            'options' => array(
                                'tableGateway'    => $this->getServiceLocator()->get('Application\Model\RegisterTable'),
                            ),
                        ),
                ),
            ),
        );
    }
}

Also it's not clear to me why you are instantiating a Controller in your validator class. You really shouldn't do that.

OTHER TIPS

I opted for a different approach.

Instead of passing the dependency from the form to the validator, I pass it from the form to the ValidatorManager, which is automatically injected on each validator that implements the ServiceLocatorAware Interface.

<?php

// Form
public function getInputFilterSpecification(){
    $filter = new InputFilter();
    $factory = new InputFactory();

    // Inject SM into validator manager
    $pm = $this->getServiceLocator()->get("ValidatorManager");

    $validatorChain = $factory->getDefaultValidatorChain();
    $validatorChain->setPluginManager($pm);

    // Your validators here..
}

// Validator
class MyValidator extends AbstractValidator implements ServiceLocatorAwareInterface {

    /**
     * SM
     * @var ServiceLocatorInterface
     */
    private $serviceLocator;

    /**
     * Validate
     */
    public function isValid($email){

        // Get the application config
        $config = $this->getServiceLocator()->getServiceLocator()->get("config");

    }

    /**
     * ServiceLocatorAwarr method
     * @param ServiceLocatorInterface $serviceLocator
     * @return \Application\Module
     */
    public function setServiceLocator(ServiceLocatorInterface $serviceLocator){
        $this->serviceLocator = $serviceLocator;
        return $this;
    }

    /**
     * ServiceLocatorAwarr method
     * @return ServiceLocatorInterface
     */
    public function getServiceLocator(){
        return $this->serviceLocator;
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top