I tried to validate a simple form in zend framework 2 for days now.
I checked the documentation and a lot of posts considering this topic but I found no solution!
I have a very simple form:
class AlimentForm extends Form
{
public function __construct($name = null)
{
parent::__construct('aliment');
$this->add(array(
'required'=>true,
'name' => 'year',
'type' => 'Text',
'options' => array(
'label' => 'Jahr',
),
));
$this->add(array(
'required'=>true,
'name' => 'number',
'type' => 'Text',
'options' => array(
'label' => 'Number',
),
));
$this->add(array(
'name' => 'submit',
'type' => 'Submit',
'attributes' => array(
'value' => 'Go',
'id' => 'submitbutton',
),
));
}
}
I created a custom InputFilter:
namespace Application\Form;
use Zend\InputFilter\InputFilter;
class AlimentInputFilter extends InputFilter {
public function init()
{
$this->add([
'name' => AlimentForm::year,
'required' => true,
'validators' => array(
array(
'name' => 'Between',
'options' => array(
'min' => 1900,
'max' => 3000,
),
),
),
]);
}
}
and finally in my controller I try to validate the form
public function alimentAction(){
$form = new AlimentForm();
$form->setInputFilter(new AlimentInputFilter());
$request = $this->getRequest();
if ($request->isPost()) {
$form->setData($request->getPost());
if ($form->isValid()) {
$year = $form->get('year')->getValue();
$number = $form->get('number')->getValue();
return array('result' => array(
"msg" => "In the Year ".$year." you get ".$number." Points"
));
}
}
return array('form' => $form);
}
It can't be that difficult, but from all those different ways to validate a form I found in the net, I'm a bit confused...
What am I missing?
Greetings and thanks in advance
U.H.
Ok, I solved the problem.
I created a Model for the aliment Form that has a year and a number attribute
and I defined an input filter within that model:
use Zend\InputFilter\InputFilter;
use Zend\InputFilter\InputFilterAwareInterface;
use Zend\InputFilter\InputFilterInterface;
class Aliment implements InputFilterAwareInterface
{
public $year;
public $number;
public function exchangeArray($data){
$this->year = (!empty($data['year']))?$data['year']:null;
$this->number = (!empty($data['number']))?$data['number']:null;
}
public function setInputFilter(InputFilterInterface $inputFilter)
{
throw new \Exception("Not used");
}
public function getInputFilter()
{
if (!$this->inputFilter) {
$inputFilter = new InputFilter();
$inputFilter->add(array(
'name' => 'year',
'required' => true,
'filters' => array(
array('name' => 'StripTags'),
array('name' => 'StringTrim'),
),
'validators' => array(
array(
'name' => 'Between',
'options' => array(
'min' => 1900,
'max' => 3000
)
)
),
));
$inputFilter->add(array(
'name' => 'number',
'required' => true,
'filters' => array(
array('name' => 'StripTags'),
array('name' => 'StringTrim'),
),
'validators' => array(
array(
'name' => 'Between',
'options' => array(
'min' => 1,
'max' => 10
)
)
),
));
$this->inputFilter = $inputFilter;
}
return $this->inputFilter;
}
}
In the action method of the controller I was able to set the InputFilter of the model to the form and voila! It worked!
public function alimentAction(){
$form = new AlimentForm();
$request = $this->getRequest();
if ($request->isPost()) {
$aliment = new \Application\Model\Aliment;
$form->setInputFilter($aliment->getInputFilter());
$form->setData($request->getPost());
if ($form->isValid()) {
$aliment->exchangeArray($form->getData());
$year = $form->get('year')->getValue();
return array(
'result' => array(
//your result
)
);
}
}
return array('form' => $form);
}
The form is correctly validated now and returns the corresponding error messages.
I hope, it help somebody whos got similar problems with validating!
In my symfony application, I use voters to check if users can access some features.
Now, I have a navbar where the menus are displayed or hidden according to those rights.
This navbar alone renders in about 2 seconds. That's a lot added to every page.
If I comment out the render_controller of the navbar, I gain 2 seconds. If I return true at the top of every voter is_granted method, I gain 1.5 seconds.
How can I solve this ? Using cache ? not using voters ? simplifying my voters ? Is it not a best practice to use voters? even if symfony has to check attributes against the list of all attributes?
My navbar generator:
<?php
namespace AppBundle\Menu;
use AppBundle\Application\Core\ExplorerManager;
use AppBundle\Entity\User\Associate;
use AppBundle\Entity\User\Role;
use Symfony\Component\Routing\Router;
use Symfony\Component\Security\Core\Authorization\AuthorizationChecker;
use Symfony\Component\Translation\Translator;
class MenuBuilder
{
/**
* #var Router
*/
private $router;
/**
* #var Translator
*/
private $translator;
/**
* #var AuthorizationChecker
*/
private $authorizationChecker;
/**
* #param Router $router
* #param Translator $translator
* #param AuthorizationChecker $authorizationChecker
*/
public function __construct(Router $router, Translator $translator, AuthorizationChecker $authorizationChecker)
{
$this->router = $router;
$this->translator = $translator;
$this->authorizationChecker = $authorizationChecker;
}
public function getFrontendHeaderMenuItems($isAuthenticated)
{
$menuItems = array(
array(
'title' => 'pricing',
'route' => 'cms',
'route_parameters' => array('dir' => 'general', 'page' => 'foodmeup_premium')
),
// array(
// 'title' => 'recipes',
// 'route' => 'explore',
// 'route_parameters' => array('object' => ExplorerManager::RECETTE)
// ),
array(
'title' => 'blog',
'route' => 'explore',
'route_parameters' => array('object' => ExplorerManager::BLOG)
),
array(
'title' => 'contact',
'route' => 'message_foodmeup'
)
);
if (false == $isAuthenticated) {
$menuItems[] = array(
'title' => 'login',
'route' => 'login'
);
}
$menuItems = $this->generateMenuRoutes(
$menuItems,
'frontend_bars',
array()
);
return $menuItems;
}
public function getBackendLeftSidebarMenuItems()
{
$menuItems = array(
array(
'title' => 'dashboard',
'icon' => 'th-large',
'route' => 'dashboard'
),
array(
'title' => 'administration',
'icon' => 'star',
'is_granted' => Role::ROLE_ADMIN,
'children' => array(
array(
'title' => 'dashboard',
'route' => 'admin_dashboard',
),
array(
'title' => 'moderation',
'route' => 'moderate_posts',
),
array(
'title' => 'users',
'route' => 'switch_user',
'is_granted' => Role::ROLE_SUPERADMIN,
),
array(
'title' => 'subscriptions',
'route' => 'grant_partner_subscription',
'is_granted' => Role::ROLE_SUPERADMIN,
)
)
), array(
'title' => 'ingredients',
'icon' => 'flask',
'children' => array(
array(
'title' => 'explore_ingredients',
'route' => 'explore',
'route_parameters' => array('object' => ExplorerManager::CONSOMMABLE)
),
array(
'title' => 'my_ingredients',
'route' => 'user_ingredients_display',
'is_granted' => Associate::READ_INGREDIENT
), array(
'title' => 'create_import',
'route' => 'edit_ingredient',
'is_granted' => Associate::EDIT_INGREDIENT
), array(
'title' => 'stock',
'route' => 'set_ingredient_stock',
'is_granted' => Associate::READ_STOCK,
), array(
'title' => "buying_cost",
'route' => 'parameter_cost',
'is_granted' => Associate::READ_COST,
)
)
), array(
'title' => 'recipes',
'icon' => 'birthday-cake',
'children' => array(
array(
'title' => 'explore_recipes',
'route' => 'explore',
'route_parameters' => array('object' => ExplorerManager::RECETTE)
),
array(
'title' => 'my_recipes',
'route' => 'user_recipes_display',
'is_granted' => Associate::READ_RECIPE
), array(
'title' => 'create',
'route' => 'edit_recipe',
'is_granted' => Associate::EDIT_RECIPE
), array(
'title' => 'print',
'route' => 'print_recipes',
'is_granted' => Associate::READ_RECIPE
)
)
), array(
'title' => 'plannings',
'icon' => 'tasks',
'is_granted' => array(Associate::READ_PLANNING, Associate::EDIT_PLANNING, Associate::DELETE_PLANNING),
'children' => array(
array(
'title' => 'my_plannings',
'route' => 'display_plannings',
'is_granted' => Associate::READ_PLANNING
), array(
'title' => 'my_models',
'route' => 'display_plannings',
'route_parameters' => array('isModel' => true),
'is_granted' => Associate::READ_PLANNING
), array(
'title' => 'create_planning',
'route' => 'edit_planning',
'is_granted' => array(Associate::EDIT_PLANNING, Associate::CREATE_MODEL)
)
)
), array(
'title' => 'orders',
'icon' => 'phone',
'is_granted' => array(Associate::READ_ORDER, Associate::EDIT_ORDER, Associate::EDIT_ORDER, Associate::DELETE_ORDER),
'children' => array(
array(
'title' => 'my_orders',
'route' => 'display_planning_orders',
'is_granted' => Associate::READ_ORDER
), array(
'title' => 'automatic_order',
'route' => 'automatic_order',
'is_granted' => Associate::EDIT_ORDER
), array(
'title' => 'edit_order',
'route' => 'edit_order',
'is_granted' => Associate::EDIT_ORDER
)
)
), array(
'title' => 'suppliers',
'icon' => 'truck',
'is_granted' => array(Associate::EDIT_SUPPLIER, Associate::READ_SUPPLIER, Associate::DELETE_SUPPLIER),
'children' => array(
array(
'title' => 'my_suppliers',
'route' => 'display_suppliers',
'is_granted' => Associate::READ_SUPPLIER
), array(
'title' => 'select',
'route' => 'user_supplier_select',
'is_granted' => Associate::EDIT_SUPPLIER
), array(
'title' => 'create',
'route' => 'edit_organization',
'route_parameters' => array('category_slug' => 'fournisseur-de-consommables'),
'is_granted' => Associate::EDIT_SUPPLIER
)
)
), array(
'title' => 'teams',
'icon' => 'users',
'is_granted' => array(Associate::EDIT_TEAM, Associate::READ_TEAM, Associate::DELETE_TEAM, Associate::MANAGE_RIGHTS),
'children' => array(
array(
'title' => 'my_teams',
'route' => 'teams_display',
), array(
'title' => 'worker_parameter',
'route' => 'worker_parameter',
'is_granted' => Associate::EDIT_TEAM,
)
)
)
);
$menuItems = $this->generateMenuRoutes($menuItems, 'backend_bars', array());
return $menuItems;
}
private function generateMenuRoutes(Array $menuItems, $domain, $isGranted)
{
foreach ($menuItems as $key => $menuItem) {
if (array_key_exists('is_granted', $menuItems[$key])) {
$rights = is_array($menuItems[$key]['is_granted']) ? $menuItems[$key]['is_granted'] : array($menuItems[$key]['is_granted']);
$rights = array_map(function ($right) {
return $this->authorizationChecker->isGranted($right);
}, $rights);
if (in_array(true, $rights) == false) {
unset($menuItems[$key]);
continue;
}
}
if (array_key_exists('route', $menuItems[$key])) {
$menuItems[$key]['uri'] = $this->router->generate($menuItems[$key]['route'], array_key_exists('route_parameters', $menuItems[$key]) ? $menuItems[$key]['route_parameters'] : array());
} else {
$menuItems[$key]['uri'] = '#/';
}
$menuItems[$key]['title'] = $this->translator->trans($menuItems[$key]['title'], array(), $domain);
if (array_key_exists('children', $menuItems[$key])) {
$menuItems[$key]['children'] = $this->generateMenuRoutes($menuItems[$key]['children'], $domain, $isGranted);
}
}
return $menuItems;
}
public function extractTitles(Array $menuItems)
{
$titles = array();
foreach ($menuItems as $key => $menuItem) {
$titles[] = $menuItems[$key]['title'];
if (array_key_exists('children', $menuItems[$key])) {
$titles = array_merge($titles, $this->extractTitles($menuItems[$key]['children']));
}
}
return $titles;
}
}
Voters have performance drawbacks. So if you need a higher performance then it's better to use ACL or optimize voters loading, because symfony loops over all voters when each security check is performed.
Lets's suppose you have 30 links in a menu and there are 20 voters. When you check access to all links in 1 loop then symfony will call voters 600 times (the most of them will return Voter::ACCESS_ABSTAIN immediately, but it still takes time and in you case it takes too much time).
Update:
Symfony added voter caching for skipping call unneeded voters if new functions supportsAttribute or supportsType returned false once.
https://symfony.com/blog/new-in-symfony-5-4-faster-security-voters
I have a model (Inmueble) with this relation:
'direccion' => array(self::BELONGS_TO, 'Direccion', 'direccion_id_direccion'),
In this example:
$criteria=new CDbCriteria;
$criteria->addCondition('name = ' .$name,'AND');
$listInmueble=new CActiveDataProvider('Inmueble',
array('criteria' => $criteria,
'pagination' => array('pageSize' => 10),
));
I accesing in the condition to the attribute name of the model Inmueble.
How can i do a CdbCriteria accesing the attributes of the relation, for example where direccion.city = 'something'?
Thanks!
try this
$criteria->with = array(
'direccion' => array(
'condition' => 'direccion.city = :something',
'params' => array(
':something' => 'someValue'
)
)
);
http://magento.localhost.com/index.php/arithmetic/adminhtml_arithmetic/edit/id/5/key/c03c12d4c338a2e4cdbb93c3d9e511a93401d19b21a13ea77cffda20cac94577/
This is what my link looks like. I am getting all values by the ID, in the edit grid page
there is a section for multiple check boxes. How can I select all the check boxes according to the result array
$fieldset-> addField('st_user_interest', 'checkboxes', array(
'label' => Mage::helper('arithmetic')->__('Interest'),
'required' => true,
'name' => 'st_user_interest[]',
'values' => array(
array(
'label' => Mage::helper('arithmetic')->__('Education'),
'value' => 'education',
'class' => 'required-one',
),
array(
'label' => Mage::helper('arithmetic')->__('Business'),
'value' => 'business',
'class' => 'required-one',
),
array(
'label' => Mage::helper('arithmetic')->__('Marketing'),
'value' => 'marketing',
'class' => 'required-one',
),
array(
'value' => 'investment',
'label' => Mage::helper('arithmetic')->__('Investment'),
'class' => 'required-one',
)
),
));
Thanks
Hi at the time of storing array field value we are storing as string after converting array to string,
So at the time of setValues() Magento looking for that same input field value as array to check the check boxes
Trick is that convert that stored string value into array and assign to that column field that will work
Package_Arithmetic_Block_Adminhtml_Arithmetic_Edit_Tab_Form
protected function _prepareForm()
{
$id = $this->htmlEscape(Mage::registry('arithmetic_data')->getIn_user_id());
$model = Mage::getModel("arithmeti/newuser")->load($id);
/* here is the stuff witch converting the stored string to array and set in st_user_interest */
$interest = $model->getSt_user_interest();
$model->setSt_user_interest(explode(',',$interest));
$form = new Varien_Data_Form();
$this->setForm($form);
$fieldset = $form->addFieldset('arithmetic_form', array('legend'=>Mage::helper('arithmetic')->__('User information')));
$fieldset-> addField('st_user_interest', 'checkboxes', array(
'label' => Mage::helper('arithmetic')->__('Interest'),
'required' => true,
'name' => 'st_user_interest[]',
'values' => array(
array(
'label' => Mage::helper('arithmetic')->__('Education'),
'value' => 'education',
),
array(
'label' => Mage::helper('arithmetic')->__('Business'),
'value' => 'business',
),
array(
'label' => Mage::helper('arithmetic')->__('Marketing'),
'value' => 'marketing',
),
array(
'value' => 'investment',
'label' => Mage::helper('arithmetic')->__('Investment'),
)
),
));
if ( Mage::getSingleton('adminhtml/session')->getArithmeticData() )
{
$form->setValues(Mage::getSingleton('adminhtml/session')->getArithmeticData());
Mage::getSingleton('adminhtml/session')->setArithmeticData(null);
} elseif ( $model->getData() ) {
//Mage::registry('arithmetic_data')->getData(); /* removing this line and adding $model->getData() inslde the $form->setValues() */
$form->setValues($model->getData());
}
return parent::_prepareForm();
}
I am trying to save data in multiple models association but the same is not saving at all. I have all set up correctly i.e. data from form is ok (debug shows all) and find also fetches the data but couldn't understand where the problem lies. My code is follows as:
Controller:
if($url == "expense_reports") { $this->set('tab_content','Invoice - Expense Reports'); $this->render('/job/invoice2');
if($this->request->is('post'))
{//debug($this->data);
$this->Event->Invoice->Expense->save($this->data); }
}
Models (Associations):
Event
public $belongsTo = array(
'EventType' => array(
'className' => 'AgencyCalendar.EventType',
'foreignKey' => 'event_type_id'
)
);
public $hasMany = array(
'Invoice' => array(
'className' => 'AgencyCalendar.Invoice',
'foreignKey' => 'event_id',
'dependent' => false
)
);
Invoice
public $belongsTo = array(
'Event' => array(
'className' => 'AgencyCalendar.Event',
'foreignKey' => 'event_id'
)
);
public $hasMany = array(
'Expense' => array(
'className' => 'AgencyCalendar.Expense',
'foreignKey' => 'invoice_id',
'dependent' => false
)
);
Expense
public $belongsTo = array(
'Invoice' => array(
'className' => 'AgencyCalendar.Invoice',
'foreignKey' => 'invoice_id'
)
);
I am also not getting any sql dump in my view for this particular action to find out what is going on actually. Also how can I save multiple rows which would be generated from my expense view. My expense view is custom url so might be it would be a cause of not showing the sql dump or is this also a cause of not saving the data at all? Please let me know what I am doing wrong?
I believe what you are looking for is saveAll. (http://book.cakephp.org/2.0/en/models/saving-your-data.html#model-saveall-array-data-null-array-options-array)
$this->Event->saveAll($this->data);
This will work as long as you have:
- the model relationships setup correctly
- the correct array attributes in $this->data