how to add form validation from controller in zend framework 2 - zend-framework2

I tried to add a validation from my controller like below. but it always shows this
if ($request->getPost('ownerType') == "Company") {
$form->getInputFilter()->get('companyName')->getValidatorChain()->addValidator('required');
}
shows error. I confused with below error.
Catchable fatal error: Argument 1 passed to Zend\Validator\ValidatorChain::addValidator() must implement interface Zend\Validator\ValidatorInterface, string given, called in E:\xampp\htdocs\hossbrag\module\WebApp\src\WebApp\Controller\JobController.php on line 177 and defined in E:\xampp\htdocs\hossbrag\vendor\zendframework\zendframework\library\Zend\Validator\ValidatorChain.php on line 100
My controller is here
<?php
namespace WebApp\Controller;
use Zend\Mvc\Controller\AbstractActionController;
use Zend\View\Model\ViewModel;
use WebApp\Entity\User;
use Zend\View\Model\JsonModel;
use vendor\mpdf\mpdf;
class JobController extends AuthenticatedController
{
public function createAction()
{
$form = new \WebApp\Form\JobpostingForm();
$form->get('companyName')->setValueOptions($company);
$checkAgreement = true;
$request = $this->getRequest();
if ($request->getPost('ownerType') == "Company") {
$form->getInputFilter()->get('companyName')->getValidatorChain()->addValidator('required');
}
}
}
What should to change in my controller to get appropriate solution.

If you encounter such a clear error, simply check out the sources ;)
First one to check would be Zend\Validator\ValidatorInterface. The Error shows you, that a Class implementing this interface is excepted. Looking at the code you'll see, the function wants a Class, not just a string.
But since you're used to ZF a little it becomes clear that you know there's other ways to add stuff. So let's take a look at Zend\InputFilter\InputFilter#add(). You'll see that the first param of the add() function indeed asks for a class implementing ValidatorInterface. But it also accepts some other stuff:
/**
* Add an input to the input filter
*
* #param array|Traversable|InputInterface|InputFilterInterface $input
* #param null|string $name
* #return InputFilter
*/
public function add($input, $name = null)
{
//...
}
It also accepts array, Traversable, InputInterface and InputFilterInterface. So choices are there.
Now, i have never done this myself and i sincerely hope this works (if not i suck!), but assuming you're using the array-syntax, all you have to do is this:
[...]->getValidatorChain()->add(array(
'type' => 'Zend\Validator\NotEmpty'
));
Let me know if this worked out for you ;)

Related

Zend 2 Hydrator Strategy restricting keys

I've been playing with the Zend Hydrator class today and just found the Naming strategies for converting the input keys on the fly. But when playing with the MapNamingStrategy in conjunction with the ObjectProperty hydrator, it seems to add properties that didn't initially exist in the object if the input array contained them.
Is there any way to restrict it from adding new properties and only populating/hydrating existing ones in the input object?
Still no response on this - what I ended up doing was using one of two scenarios but it is still not ideal. The first is to use Class Reflection myself to get a list of keys that are accessible or to search for standard name accessors for same. (this, of course, would not find magic method accessors)
The second was to pre-define a map that didn't only include mismatched key->property mappings but also included all the one-to-one (matched) key->property mappings then filter the input using PHP's array functions prior to running the hydration using the map's key/value pairs. But this kind of defeats the purpose of using hydration as by that point in time, I may as well have used a foreach loop instead. And it eliminates any ability to use abstract destinations in that you have to know all potential input/output key->property relationships in advance.
I ended up doing my own implementation of the first method (again, that will not necessarily handle magic method accessors) which looks for public properties and/or public accessors fitting the standard camel-cased setPropertyName()/getPropertyName() accessor methods.:
<?php
/**
* simple object hydrator using class reflection to find publicly accessible properties and/or methods
*
* Created by PhpStorm.
* User: scottw
* Date: 12/12/16
* Time: 12:06 PM
*/
namespace Finao\Util;
class SimpleHydrator
{
/**
* whether to reset the keyMap following each hydration to clear the hydrator for other data/object pairs
*
* #var bool $resetMap
*/
private static $resetMap = true;
/**
* associative array of key mappings between incoming data and object property names/accessors
* #var array $keyMap
*/
private static $keyMap = array();
public static function setKeyMap($map) {
if(self::is_assoc($map))
static::$keyMap = $map;
}
public static function populateObject(&$targetObject, $dataArray)
{
if (self::is_assoc($dataArray) && is_object($targetObject)) {
// step through array elements and see if there are matching properties or methods
try {
foreach ($dataArray as $k => $v) {
$key = $k;
if(self::is_assoc(static::$keyMap) && array_key_exists($k))
$key = static::$keyMap[$k];
// if original value contains an object, try populating it if the associated value is also array
$origVal = self::getObjectPropertyValue($targetObject, $key);
if (is_object($origVal) && self::is_assoc($v)) {
self::populateObject($origVal, $v);
$v = $origVal;
}
$accessor = 'set' . ucfirst($key);
if (in_array($key, self::getObjectPublicProperties($targetObject)))
$targetObject->$key = $v;
elseif (in_array($accessor, self::getObjectPublicMethods($targetObject)))
$targetObject->$accessor($v);
}
} catch (\Exception $d) {
// do something with failures
}
if(static::$resetMap) static::$keyMap = array();
}
return $targetObject;
}
public static function getObjectPropertyValue($object, $property)
{
$objectReflection = new \ReflectionClass($object);
if ($objectReflection->hasProperty($property) && $objectReflection->getProperty($property)->isPublic())
return $object->$property;
else {
$accessor = 'get' . ucfirst($property);
if ($objectReflection->hasProperty($accessor) && $objectReflection->getMethod($accessor)->isPublic())
return $object->$accessor();
}
}
public static function getObjectPublicProperties($object)
{
if (is_object($object)) {
$publicProperties = array();
$objectReflection = new \ReflectionClass($object);
foreach ($objectReflection->getProperties(\ReflectionProperty::IS_PUBLIC) as $p)
array_push($publicProperties, $p->name);
return $publicProperties;
}
}
public static function getObjectPublicMethods($object)
{
if (is_object($object)) {
$publicMethods = array();
$objectReflection = new \ReflectionClass($object);
foreach ($objectReflection->getMethods(\ReflectionMethod::IS_PUBLIC) as $p)
array_push($publicMethods, $p->name);
return $publicMethods;
}
}
/**
* Determine if a variable is an associative array.
*
* #param mixed Input variable
* #return boolean If the input variable is an associative array.
* #see http://us2.php.net/manual/en/function.is-array.php
*/
public static function is_assoc($array) {
return (is_array($array) && 0 !== count(array_diff_key($array, array_keys(array_keys($array)))));
}
}
I eventually added a simple key mapping ability to it. (Note that this has not been rigorously tested and, as the name suggests, is just a simple solution.)

SYMFONY FORM ChoiceType, multiple=>true. How to by pass the need to implement Data Transformers

In a SYMFONY FORM (ORM is not use (PDO is used for DB query instead)).
I have a class MyEntityType in which the buildForm function has:
$builder->add('my_attribute',ChoiceType::class,array(
'choices'=>$listForMyAttribute,
'multiple'=>'true',
'attr'=>array('data-native-menu'=>'false'),
'label'=>'Multiple Select on my attribute'
));
My attribute is an array of an entity named MyEntity which has:
/**
* #Assert\NotBlank()
*/
private $myAttribute;
With a getter and a setter for that variable $myAttribute.
When I submit the form in the Controller, it doesn't pass the validation check and logs this error:
Unable to reverse value for property path "myAttribute" : Could not find all matching choices for the given values.
When I start to look for solution around this error message, it leads to something named "How to Use Data Transformers" in SYMFONY Cookbook; And it seems a solution would involve to create new Class and write a lot of code for something that one should be able to by-pass in a much straight forward way.
Does anyone have an idea?
My problem was that my array $listForMyAttribute was defined in the buildForm() function and its definition was relying on some conditional.
The conditional to make the array were met when this one was displayed for the first time.
After pushing the submit button, the buildForm was regenerated in the Controller, this second time, the condition were not met to make the array $listForMyAttribute as it was on the first display. Hence the program was throwing a "contraint not met error" because the value submited for that field could not be find.
Today I face exactly the same problem. Solution is simple as 1-2-3.
1) Create utility dummy class DoNotTransformChoices
<?php
namespace AppBundle\DataTransformer;
use Symfony\Component\Form\Extension\Core\ChoiceList\ChoiceListInterface;
class DoNotTransformChoices implements ChoiceListInterface
{
public function getChoices() { return []; }
public function getValues() { return []; }
public function getPreferredViews() { return []; }
public function getRemainingViews() { return []; }
public function getChoicesForValues(array $values) { return $values; }
public function getValuesForChoices(array $choices) { return $choices; }
public function getIndicesForChoices(array $choices) { return $choices; }
public function getIndicesForValues(array $values) { return $values; }
}
2) Add to your field the following additional option:
...
'choice_list' => new DoNotTransformChoices,
...
3) Congratulations!

Zend Framework 2 - How to give declare folder path in terms of "use" and "namespace"

I am facing problem while creating adapter object in controller file named Listcontroller.My code is
namespace Blog\Controller;
use Blog\Service\PostServiceInterface;
use Zend\Mvc\Controller\AbstractActionController;
use Zend\View\Model\ViewModel;
use Zend\Db\Sql\Sql;
use Zend\Db\Adapter\Adapter;
class ListController extends AbstractActionController
{
/**
* #var \Blog\Service\PostServiceInterface
*/
protected $postService;
public function __construct(PostServiceInterface $postService)
{
$this->postService = $postService;
}
public function indexAction()
{
$adapter = new Zend\Db\Adapter\Adapter($configArray);
print_r($adapter);
//code ....
}
}
here it is serching to find Zend\Db\Adapter\Adapter inside Blog\Controller.
Error is -> Fatal error: Class 'Blog\Controller\Zend\Db\Adapter\Adapter' not found. Can anybody tell me please how can i move two folder back from above path. so that i can get proper object??
You don't need the fully qualified class name (FQCN) when instantiating a new Adapter since you declare that class path via use statement:
use Zend\Db\Adapter\Adapter;
Change this block
public function indexAction()
{
$adapter = new Zend\Db\Adapter\Adapter($configArray);
print_r($adapter);
}
to
public function indexAction()
{
$adapter = new Adapter($configArray);
print_r($adapter);
}
It should work.
Anyway, new \Zend\Db\Adapter\Adapter($configArray) also works (notice the first backslash) but its longer, harder to type and less readable than first example.
You may also want to read namespace aliasing/importing section of the documentation.

Generics type parameter wildcard

I would like to create an abstract class which takes a type parameter and the constructor of that class should be passed another Action eg.
abstract class Action<Tc> {
public function __construct(private ?Action<*> $onSuccess = null) {}
}
How can I express a type parameter wildcard ie. "?" (Java) or "_" (Scala) in Hack?
Hack doesn't have wildcard type parameters right now, so the closest you can get is actually specifying a dummy type parameter that you don't actually need, e.g.,
abstract class Action<Tc, Ta> {
public function __construct(private ?Action<Ta> $onSuccess = null) {}
// ...
}
Depending on how exactly you use the $onSuccess member variable, you may want it to be some specific subclass of Action<T> to be determined later, and so you may want something like this:
abstract class Action<Tc, Ta, To as Action<Ta>> {
public function __construct(private ?To $onSuccess = null) {}
// ...
}
However, I question whether the "dummy" types above above are really a dummy -- the vast, vast majority of use cases of Action<T> are going to care what exactly the T is, otherwise how exactly would you use the Action<T>? (There are certainly rare cases where you don't care about the T at a callsite, but they are, well, rare and so I encourage you to consider whether that is actually your case as you build out this functionality.)
Not sure about a wildcard, but could this achieve what you want?
<?hh
abstract class Action<T1 as Action, T2> {
public function __construct(private ?T1 $onSuccess = null, private ?T2 $bla = null) {}
}
class ActionA<T1 as Action, T2> extends Action<T1, T2> {}
class ActionB<T1 as Action, T2> extends Action<T1, T2> {}
class ActionC<T1 as Action, T2> extends Action<T1, T2> {}
$action = new ActionA(new ActionB(new ActionC(null)));
var_dump($action);
When I run this against HHVM 3.1.0, I get:
object(ActionA)#1 (2) {
["onSuccess":"Action":private]=>
object(ActionB)#2 (2) {
["onSuccess":"Action":private]=>
object(ActionC)#3 (2) {
["onSuccess":"Action":private]=>
NULL
["bla":"Action":private]=>
NULL
}
["bla":"Action":private]=>
NULL
}
["bla":"Action":private]=>
NULL
}
And the 3.1.0 type checker also returns "No errors!".
However, the T1 as Action statement on the abstract class doesn't appear to be enforcing. For instance, I can change the instantiation line to:
$action = new ActionA(new ActionB(new ActionC(new DateTime())));
And it hums along fine, with the typechecker returning no errors still. And this is after taking the class definitions out into their own file with <?hh // strict.
So not really your answer, but perhaps close? The behavior above might suggest Hack has some issues with this sort of pattern?

ZF2: How to attach listener on the event in the Module class?

I want to set a basePath to be the same for every component of my Mvc for a given request. I mean when I call these methods I want to get the same result, lets say '/spam/ham/':
echo $this->headLink()->prependStylesheet($this->basePath() . '/styles.css') // $this->basePath() has to be '/spam/ham/'
$this->getServiceLocator()
->get('viewhelpermanager')
->get('headLink')
->rependStylesheet($this->getRequest()->getBasePath() . '/styles.css') // $this->setRequest()->getBasePath() has to be /spam/ham/
How to set the basePath for the first case I have found already, here's my question. By the way, the original manual doesn't have any info I received from the answer.
And now the second one - the basePath has to be set in the Request:
$this->getRequest()->getBasePath()
Here I found some answer that in fact doesn't work at all http://zend-framework-community.634137.n4.nabble.com/Setting-the-base-url-in-ZF2-MVC-td3946284.html. As said here StaticEventManager is deprecated so I changed it with SharedEventManager :
// In my Application\Module.php
namespace Application;
use Zend\EventManager\SharedEventManager
class Module {
public function init() {
$events = new SharedEventManager();
$events->attach('bootstrap', 'bootstrap', array($this, 'registerBasePath'));
}
public function registerBasePath($e) {
$modules = $e->getParam('modules');
$config = $modules->getMergedConfig();
$app = $e->getParam('application');
$request = $app->getRequest();
$request->setBasePath($config->base_path);
}
}
}
And in my modules/Application/configs/module.config.php I add:
'base_path' => '/spam/ham/'
But it desn't work. The problems are:
1) The run never comes to the registerBasePath function. But it has to. I've attached an event with the listener in the init function.
2) When I change SharedEventManager for just EventManager it happens to come to the registerBasePath function but an exeption is thrown:
Fatal error: Call to undefined method Zend\EventManager\EventManager::getParam()
What do I do wrong? Why the run of the program doesn't come to the registerBasePath function? If this is the only way to set the basePath globally then how to do it right?
I know the documentation is lacking of these kinds of things. But you are right in the way to approach this:
Be early (so at bootstrap)
Grab the request from the application
Set the base path in the request
The docs are lacking this information and the post you refer to is quite old. The fastest and easiest way to do this is using the onBootstrap() method:
namespace MyModule;
class Module
{
public function onBootstrap($e)
{
$app = $e->getApplication();
$app->getRequest()->setBasePath('/foo/bar');
}
}
If you want to grab the base path from your config, you can load the service manager there:
namespace MyModule;
class Module
{
public function onBootstrap($e)
{
$app = $e->getApplication();
$sm = $app->getServiceManager();
$config = $sm->get('config');
$path = $config->base_path;
$app->getRequest()->setBasePath($path);
}
}

Resources