I want to use NoRocordExists to validate if email exists before insert the information inside the mysql DB but i don't get how can i call $dbapater.
This is my code of my inputfilter class
$norecord_exists = new NoRecordExists(
array(
'table' => 'users',
'field' => 'email',
'adapter' => $dbadapter
)
);
$norecord_exists->setMessage('Email already exists !', 'recordFound');
$this->add(array(
'name' => 'email',
'required' => true,
'filters' => array(
array('name' => 'StringTrim'),
),
'validators' => array(
$norecord_exists,
array(
'name'=>'EmailAddress',
'options'=> array(
'allowWhiteSpace'=>true,
'messages' => array(
\Zend\Validator\EmailAddress::INVALID_HOSTNAME=>'Email incorrecto',
),
),
),
)
));
With ZF2, I advise you to use FactoryInterface like this :
UserFormFactory.php
<?php
namespace User\Form\Service;
use User\Form\UserForm;
use Zend\ServiceManager\FactoryInterface;
use Zend\ServiceManager\ServiceLocatorInterface;
class UserFormFactory implements FactoryInterface
{
/**
* #param ServiceLocatorInterface $serviceLocator
* #return UserForm
*/
public function createService(ServiceLocatorInterface $serviceLocator)
{
/* #var ServiceLocatorInterface $sl */
$sl = $serviceLocator->getServiceLocator();
$form = new UserForm();
$form->setDbAdapter($sl->get('Zend\Db\Adapter\Adapter'));
return $form;
}
}
UserForm.php
<?php
namespace User\Form;
use Zend\Db\Adapter\AdapterInterface;
use Zend\Form\Form;
use Zend\InputFilter\InputFilterProviderInterface;
class UserForm extends Form implements InputFilterProviderInterface
{
/**
* #var AdapterInterface
*/
protected $dbAdapter;
/**
* Initialisation
*/
public function init()
{
$this->add([
'name' => 'email',
'type' => 'Email',
'options' => [
'label' => 'Email',
],
'attributes' => [
'class' => 'form-control',
'required' => 'required',
],
]);
// ...
$this->add([
'name' => 'submit',
'type' => 'Submit',
'attributes' => [
'value' => 'Connexion',
'class' => 'btn btn-default',
],
]);
}
/**
* InputFilter
*
* #return array
*/
public function getInputFilterSpecification()
{
return [
'email' => [
'required' => true,
'filters' => [
['name' => 'StripTags'],
['name' => 'StringTrim'],
['name' => 'StringToLower'],
],
'validators' => [
[
'name' => 'EmailAddress',
], [
'name' => 'Db\NoRecordExists',
'options' => [
'table' => 'user',
'field' => 'email',
'adapter' => $this->getDbAdapter(),
],
],
],
],
// ...
];
}
/**
* #return AdapterInterface
*/
public function getDbAdapter()
{
return $this->dbAdapter;
}
/**
* #param AdapterInterface $dbAdapter
* #return UserForm
*/
public function setDbAdapter(AdapterInterface $dbAdapter)
{
$this->dbAdapter = $dbAdapter;
return $this;
}
}
module.config.php
return [
'form_elements' => [
'factories' => [
'UserForm' => 'User\Form\Service\UserFormFactory',
],
],
];
Finally, in your controller
$form = $this->getServiceLocator('FormElementManager')->get('UserForm');
//..
if ($form->isValid()) // ...
You need to move this code
$norecord_exists = new NoRecordExists(
array(
'table' => 'users',
'field' => 'email',
'adapter' => $dbadapter
)
);
$norecord_exists->isValid(EMAIL_FROM_THE_FORM_FIELD) {
return false; //email exists
}
return true; // email doen't exists
in your Controller or in a separate service/factory. $dbadapter usually holds the instance to your Zend\Db\Adaptr\Adapter or any other configuration you have.
Related
setting default/ selected option for choice field in symfony3 sonata admin bundle?
For example :
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
/**
* #inheritdoc
*/
public function configureFormFields(FormMapper $formMapper) {
parent::configureFormFields($formMapper);
$formMapper->add('type', ChoiceType::class, [
'label' => 'config.label_type',
'choices' => [
'config.label_permanent' => 'permanent',
'config.label_automatic' => 'automatic',
'config.label_temporary' => 'temporary'
],
'required' => false
]);
}
How to make the _permanent_ as selected value ?
This post doesn't help me out
setting default value in symfony2 sonata admin bundle
You can try with something like this:
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
/**
* #inheritdoc
*/
public function configureFormFields(FormMapper $formMapper) {
parent::configureFormFields($formMapper);
$subject = $this->getSubject();
if (null === $subject->getId()) {
$subject->setType('permanent');
}
$formMapper->add('type', ChoiceType::class, [
'label' => 'config.label_type',
'choices' => [
'config.label_permanent' => 'permanent',
'config.label_automatic' => 'automatic',
'config.label_temporary' => 'temporary'
],
'required' => false
]);
}
I stuck With this Issue in Zd2 and knocking my head from last 2 days but not come up with any solution. Will be very Appreciable If anyone Can help me out with the below given error.
Argument 1 passed to Application\Controller\IndexController::__construct() must be an instance of Application\Model\EmployeeTable, none given
Here is my Application Module Config file module.config.php
namespace Application;
use Zend\Router\Http\Literal; use Zend\Router\Http\Segment; use
Zend\ServiceManager\Factory\InvokableFactory;
return [
[
'controllers' => [
'invokables' => [
'Application\Controller\Index' => 'Application\Controller\IndexController',
],
'factories' => [
'Application\Controller\Index' => 'Application\Factory\IndexControllerFactory'
],
]
],
'router' => [
'routes' => [
'home' => [
'type' => Literal::class,
'options' => [
'route' => '/',
'defaults' => [
'controller' => Controller\IndexController::class,
'action' => 'index',
],
],
],
'application' => [
'type' => Segment::class,
'options' => [
'route' => '/application[/:action]',
'defaults' => [
'controller' => Controller\IndexController::class,
'action' => 'index',
],
],
],
],
],
'view_manager' => [
'display_not_found_reason' => true,
'display_exceptions' => true,
'doctype' => 'HTML5',
'not_found_template' => 'error/404',
'exception_template' => 'error/index',
'template_map' => [
'layout/layout' => __DIR__ . '/../view/layout/layout.phtml',
'application/index/index' => __DIR__ . '/../view/application/index/index.phtml',
'error/404' => __DIR__ . '/../view/error/404.phtml',
'error/index' => __DIR__ . '/../view/error/index.phtml',
],
'template_path_stack' => [
__DIR__ . '/../view',
],
], ];
Application Index Controller
table = $table;
}
public function indexAction() {
$view = new ViewModel([
'data' => $this->table->fetchAll(),
]);
return $view;
} }
Module.php file
class Module implements ConfigProviderInterface {
const VERSION = '3.0.3-dev';
public function getConfig()
{
return include __DIR__ . '/../config/module.config.php';
}
public function getServiceConfig() {
return [
'factories' => [
Model\EmployeeTable::class => function ($container) {
$tableGateway = $container>get(Model\EmployeeTableGateway::class);
$table = new Model\EmployeeTable($tableGateway);
return $table;
},
Model\EmployeeTableGateway::class => function ($container) {
$dbAdapter = $container->get(AdapterInterface::class);
$resultSetPrototype = new ResultSet();
$resultSetPrototype->setArrayObjectPrototype(new Employee());
return new TableGateway('employee', $dbAdapter, null, $resultSetPrototype);
},
],
];
}
public function getControllerConfig() {
return [
'factories' => [
Controller\IndexController::class => function($container) {
return new Controller\IndexController(
$container->get(EmployeeTable::class)
);
},
],
];
} }
Model Employee
class Employee {
public $id;
public $emp_name;
public $emp_job;
public function exchangeArray($data) {
$this->id = (!empty($data['id'])) ? $data['id'] : null;
$this->emp_name = (!empty($data['emp_name'])) ? $data['emp_name'] : null;
$this->emp_job = (!empty($data['emp_job'])) ? $data['emp_job'] : null;
} }
Model EmployeeTable
use Zend\Db\TableGateway\TableGateway;
use Zend\Db\TableGateway\TableGatewayInterface;
class EmployeeTable {
protected $tableGateway;
public function __construct(TableGatewayInterface $tableGateway) { $this->tableGateway = $tableGateway; }
public function fetchAll() {
$resultSet = $this->tableGateway->select();
return $resultSet;
} }
Please help !
I the above Module.php, either write on top of the class
use Model\EmployeeTable;
Or, set an aliases to "Model\EmployeeTable::class"
public function getServiceConfig() {
return [
'factories' => [
Model\EmployeeTable::class => function ($container) {
$tableGateway = $container>get(Model\EmployeeTableGateway::class);
$table = new Model\EmployeeTable($tableGateway);
return $table;
},
Model\EmployeeTableGateway::class => function ($container) {
$dbAdapter = $container->get(AdapterInterface::class);
$resultSetPrototype = new ResultSet();
$resultSetPrototype->setArrayObjectPrototype(new Employee());
return new TableGateway('employee', $dbAdapter, null, $resultSetPrototype);
},
],
'aliases' => array(
EmployeeTable::class => Model\EmployeeTable::class
)
];
}
I'm doing a registration form in ZF2, but I don't get how to validate. Validation seems not working.
I'm adding the validators array, but it doesn't work anyways. I don't know how can I fix that.
This is my code of controller:
namespace Application\Controller;
use Zend\Mvc\Controller\AbstractActionController;
use Zend\View\Model\ViewModel;
use Application\Form\Formularios;
use Zend\Db\Adapter\Adapter;
use Application\Modelo\Entity\Usuarios;
class FormularioController extends AbstractActionController
{
public $dbAdapter;
public function indexAction()
{
return new ViewModel();
}
public function registroAction()
{
if($this->getRequest()->isPost())
{
$this->dbAdapter=$this->getServiceLocator()->get('Zend\Db\Adapter');
$u=new Usuarios($this->dbAdapter);
//echo "se recibiĆ³ el post";exit;
$data = $this->request->getPost();
$u->addUsuario($data);
return $this->redirect()->toUrl($this->getRequest()->getBaseUrl().'/application/formulario/registro/1');
}else
{
//zona del formulario
$form=new Formularios("form");
$id = (int) $this->params()->fromRoute('id', 0);
$valores=array
(
"titulo"=>"Registro de Usuario",
"form"=>$form,
'url'=>$this->getRequest()->getBaseUrl(),
'id'=>$id
);
return new ViewModel($valores);
}
}
}
this is my form code with validator
class Formularios extends Form
{
public function __construct($name = null)
{
parent::__construct($name);
$this->add(array(
'name' => 'name',
'required' => true,
'allow_empty' => false,
'options' => array(
'label' => 'Nombre Completo',
),
'attributes' => array(
'type' => 'text',
'class' => 'input'
),
'filters' => [ ['name' => 'StringTrim'], ],
'validators' => array(
array(
'name' => 'NotEmpty',
'options' => array(
'messages' => array(
\Zend\Validator\NotEmpty::IS_EMPTY => 'Ingrese Nombres.',
))))
));
$this->add(array(
'name' => 'lastname',
'required' => true,
'options' => array(
'label' => 'Apellido',
),
'attributes' => array(
'type' => 'text',
'class' => 'input'
),
'validators' => array(
array(
'name' => 'NotEmpty',
'options' => array(
'messages' => array(
\Zend\Validator\NotEmpty::IS_EMPTY => 'Ingrese Apellidos.',
))))
));
Thanks in advance
First problem.
$data = $this->request->getPost(); should be $data = $this->getRequest()->getPost();
Second problem is that you call your validators direclty when you build your form in the view, which is wrong. The right way to do is via an inputFilter. Now, there are many ways to to this, for example: with or without a factory called from your model or via the for class with a form element manager
I will show you the model way with a factory since it's easier for new comers.
namespace MyModule\Model;
use Zend\InputFilter\InputFilter;
use Zend\InputFilter\Factory as InputFactory;
use Zend\InputFilter\InputFilterAwareInterface;
use Zend\InputFilter\InputFilterInterface;
class MyModel implements InputFilterAwareInterface
{
/**
* #var null $_inputFilter inputFilter
*/
private $_inputFilter = null;
// some more code like exhnageArray get/set method
public function setInputFilter(InputFilterInterface $inputFilter)
{
throw new \Exception("Not used");
}
public function getInputFilter()
{
if (!$this->inputFilter) {
$inputFilter = new InputFilter();
$factory = new InputFactory();
$inputFilter->add(
$factory->createInput([
'name' => 'id',
'required' => false,
'filters' => [
['name' => 'Int'],
],
])
);
$inputFilter->add(
$factory->createInput([
"name"=>"title",
"required" => true,
'filters' => [
['name' => 'StripTags'],
['name' => 'StringTrim'],
],
'validators' => [
['name' => 'NotEmpty'],
[
'name' => 'StringLength',
'options' => [
'encoding' => 'UTF-8',
'min' => 1,
'max' => 200,
],
],
],
])
);
$inputFilter->add(
$factory->createInput([
"name"=>"text",
"required" => true,
'filters' => [
['name' => 'StripTags'],
['name' => 'StringTrim'],
],
'validators' => [
['name' => 'NotEmpty'],
[
'name' => 'StringLength',
'options' => [
'encoding' => 'UTF-8',
'min' => 1,
],
],
],
])
);
$this->inputFilter = $inputFilter;
}
return $this->inputFilter;
}
}
Third proble. DO NOT EVER use serviceManager in controller. It's a really really really bad practice. Instead use a factory.
I recently started learning ZF2 and hope someone can help me with this.
I am working my way through Rob Allen's Zend Framework 2 Tutorial (many thanks to #rob-allen).
Also I use a solution of #AlloVince and #Maciej How to set db adapter to Validator RecordExists in Zend Framework 2 (many thanks to both authors for it) and I confused because didn't to use this solution in editAction.
I see Fatal error: Call to a member function get() on a non-object in 'adapter' => $this->getServiceLocator()->get('Zend\Db\Adapter\Adapter').
1) In the Module.php added
public function getServiceConfig()
{
return array(
'invokables' => array(
'RegionModel' => 'FcLibraries\Model\Region', //<-- added it
),
'factories' => array(
'FcLibraries\Model\RegionTable' => function ($sm) {
$dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
$table = new RegionTable($dbAdapter);
return $table;
},
),
);
}
2) In the Region.php added
/**
* #var
*/
protected $serviceLocator;
/**
* #param \Zend\ServiceManager\ServiceLocatorInterface $serviceLocator
* #return Library
*/
public function setServiceLocator(ServiceLocatorInterface $serviceLocator)
{
$this->serviceLocator = $serviceLocator;
return $this;
}
/**
* #return \Zend\ServiceManager\ServiceLocatorInterface
*/
public function getServiceLocator()
{
return $this->serviceLocator;
}
and
$inputFilter->add($factory->createInput(array(
'name' => 'name',
'required' => true,
'filters' => $this->_filters,
'validators' => array(
array(
'name' => 'StringLength',
'options' => array(
'encoding' => 'UTF-8',
'min' => 1,
'max' => 30,
),
),
array(
'name' => 'Db\NoRecordExists',
'options' => array(
'table' => $this->table,
'field' => 'name',
//'exclude' => array(
// 'field' => 'id',
// 'value' => $this->id
//),
'adapter' => $this->getServiceLocator()->get('Zend\Db\Adapter\Adapter'),
),
),
),
)));
3) In the RegionController.php in addAction using
$model = $this->getServiceLocator()->get('RegionModel');
instead of $model = new Region();.
This works fine for addAction, But I can not understand how I should use it in editAction.
My
public function editAction()
{
$id = (int)$this->params()->fromRoute('id', 0);
if (!$id) {
return $this->redirect()->toRoute('zfcadmin/region', array(
'action' => 'add'
));
}
$data = $this->getRegionTable()->get($id);
$form = new RegionForm();
$form->bind($data);
$form->get('submitBtn')->setAttribute('value', 'Save');
$request = $this->getRequest();
if ($request->isPost()) {
$form->setInputFilter($data->getInputFilter());
$form->setData($request->getPost());
if ($form->isValid()) {
$this->getRegionTable()->save($form->getData());
return $this->redirect()->toRoute('zfcadmin/regions');
}
}
return array(
'id' => $id,
'form' => $form,
);
}
My RegionTable has the following code:
/**
* #param \Zend\Db\Adapter\Adapter $adapter
*/
public function __construct(Adapter $adapter)
{
$this->adapter = $adapter;
$this->resultSetPrototype = new ResultSet();
$this->resultSetPrototype->setArrayObjectPrototype(new Region());
$this->initialize();
}
public function get($id)
{
$id = (int)$id;
$rowSet = $this->select(array('id' => $id));
$row = $rowSet->current();
if (!$row) {
throw new \Exception("Could not find row $id");
}
return $row;
}
Many thanks to all who will answer my question.
Best regards, Ruslan.
Instead of using the form filter from the entity which you gathered from the table you should instantiate a new entity via the service manager to use the database adapter.
You have a few options:
Move the input filter to its own class and instantiate via the service manager so your database adapter is injected.
Change the prototype object in the table gateway factory to be instantiated via the service manager factory.
Instantiate a separate entity via the service manager and get the input filter from there.
I personally would go for option 1 as it separates the code better.
Some examples:
Option 1 (my choice):
This involves moving the filter to its own file and class, creating a factory for it whilst injecting the database adapter. We will then, in the controller, get the filter via the service manager and apply the filter to the form.
So first move your filter to a file in ModName\src\ModName\Form\RegionFilter.php, obviosly replacing ModName with your module name.
and change the code to like so:
<?php
namespace Region\Form;
use Zend\InputFilter\Factory as InputFactory;
use Zend\InputFilter\InputFilter;
use Zend\InputFilter\InputFilterAwareInterface;
use Zend\InputFilter\InputFilterInterface;
use Zend\Db\Adapter\Adapter;
class RegionFilter implements InputFilterAwareInterface {
/**
* #var inputFilter
*/
protected $inputFilter;
/**
* #var Database Adapter
*/
protected $dbAdapter;
/**
* #param \Zend\InputFilter\InputFilterInterface $inputFilter
* #throws \Exception
*/
public function setInputFilter(InputFilterInterface $inputFilter) {
throw new \Exception("Not used");
}
/**
* #param \Zend\Db\Adapter $dbAdapter
*/
public function __construct(Adapter $dbAdapter) {
$this->dbAdapter = $dbAdapter;
}
/**
*
* #return Zend\Db\Adapter
*/
public function getDbAdapter() {
return $this->dbAdapter;
}
/**
* #return \Zend\InputFilter\InputFilter
*
* Get the input filter (build it first)
*/
public function getInputFilter() {
if (!$this->inputFilter) {
$inputFilter = new InputFilter();
$factory = new InputFactory();
$inputFilter->add($factory->createInput(array(
'name' => 'name',
'required' => true,
'filters' => $this->_filters,
'validators' => array(
array(
'name' => 'StringLength',
'options' => array(
'encoding' => 'UTF-8',
'min' => 1,
'max' => 30,
),
),
array(
'name' => 'Db\NoRecordExists',
'options' => array(
'table' => $this->table,
'field' => 'name',
//'exclude' => array(
// 'field' => 'id',
// 'value' => $this->id
//),
'adapter' => $this->getDbAdapter(),
),
),
),
)));
$this->inputFilter = $inputFilter;
}
return $this->inputFilter;
}
}
?>
You would then create a factory like so in Module.php:
public function getServiceConfig()
{
return array(
'factories' => array(
'ModName\Form\RegionFilter' => function($sm) {
$dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
return new RegionFilter($dbAdapter);
},
),
);
}
And finally in your controller, just do the following:
if ($request->isPost()) {
$filter = $this->getServiceLocator()->get('ModName\Form\RegionFilter');
$form->setInputFilter($filter->getInputFilter());
$form->setData($request->getPost());
if ($form->isValid()) {
$this->getRegionTable()->save($form->getData());
return $this->redirect()->toRoute('zfcadmin/regions');
}
}
Option 2:
This involves constructing your table with an instance of Region injected. Then you can set the prototype to this.
So in your table construct:
public function __construct(Adapter $adapter, Region $region)
{
$this->adapter = $adapter;
$this->resultSetPrototype = new ResultSet();
$this->resultSetPrototype->setArrayObjectPrototype($region);
$this->initialize();
}
And then your factory:
public function getServiceConfig()
{
return array(
'invokables' => array(
'RegionModel' => 'FcLibraries\Model\Region',
),
'factories' => array(
'FcLibraries\Model\RegionTable' => function ($sm) {
$region = $sm->get('RegionModel');
$dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
$table = new RegionTable($dbAdapter,$region);
return $table;
},
),
);
}
You should be able to leave the rest of the code as is. Eg the controller. Now I have not tested this method so I'm not 100% it will work, but I think it should. The other two methods I have used previously myself.
Option 3 (the simplest):
This involves getting a separate region model via the service manager and using that to apply the input filter to the form.
public function editAction()
{
$id = (int)$this->params()->fromRoute('id', 0);
if (!$id) {
return $this->redirect()->toRoute('zfcadmin/region', array(
'action' => 'add'
));
}
$data = $this->getRegionTable()->get($id);
$form = new RegionForm();
$form->bind($data);
$form->get('submitBtn')->setAttribute('value', 'Save');
$request = $this->getRequest();
if ($request->isPost()) {
$region = $this->getServiceLocator()->get('RegionModel');
$form->setInputFilter($region->getInputFilter());
$form->setData($request->getPost());
if ($form->isValid()) {
$this->getRegionTable()->save($form->getData());
return $this->redirect()->toRoute('zfcadmin/regions');
}
}
return array(
'id' => $id,
'form' => $form,
);
}
I have not tested the code but you should get the gist. Any questions just ask.
For doing the validation for "Username already exists or not", Do the following simple way of Service Manager config settings like:
// config/autoload/global.php
return array(
'db' => array(
'driver' => 'Pdo',
'dsn' => 'mysql:dbname=zf2tutorial;host=localhost',
),
'service_manager' => array(
'factories' => array(
'Zend\Db\Adapter\Adapter' => function ($serviceManager) {
$adapterFactory = new Zend\Db\Adapter\AdapterServiceFactory();
$adapter = $adapterFactory->createService($serviceManager);
\Zend\Db\TableGateway\Feature\GlobalAdapterFeature::setStaticAdapter($adapter);
return $adapter;
}
),
)
);
and add the following array into getInputFilter():
array(
'table' => 'users',
'field' => 'username',
'adapter' => \Zend\Db\TableGateway\Feature\GlobalAdapterFeature::getStaticAdapter();
)
I have a ZF2 application that I need to pass custom database queries from. I have set up my database credentials in local.php and global.php. From a class, how do I get a database object?
This is my global.php:
return array(
'db' => array(
'driver' => 'Pdo',
'dsn' => 'mysql:dbname=database_name;host=localhost',
'driver_options' => array(
PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES \'UTF8\''
),
),
'service_manager' => array(
'factories' => array(
'Zend\Db\Adapter\Adapter' => 'Zend\Db\Adapter\AdapterServiceFactory',
),
),
);
To get the DB object
In Module.php
public function getServiceConfig()
{
return array(
'factories' => array(
'db_adapter' => function($sm) {
$config = $sm->get('Configuration');
return new \Zend\Db\Adapter\Adapter($config['db']);
},
'xyz_class_name' => function ($sm) {
return new \WhatEver\Model\xyzMapper($sm->get('db_adapter'));
},
),
);
}
In xyzMapper
namespace WhatEver\Model;
use Zend\Db\Adapter\Adapter;
class xyzMapper
{
protected $adapter;
/**
* Make the Adapter object avilable as local prtected variable
* #param Adapter $adapter - DB PDO PgSQL conn
*/
public function __construct(Adapter $adapter = null)
{
$this->adapter = $adapter;
}
/**
* #return result object
*/
public function getdata()
{
$sql = "SELECT * FROM tbl";
$statement = $this->adapter->query($sql);
return $statement->execute();
}
}