Adding multiselect dropdown in Admin customer details form in prestashop - admin

I have added a multiselect dropdown field in customer adding form in admin. I have created new field in database. But I am not getting how to store the value of this new field to database. Please help
I have added this code to AdminCustomersController.php
array(
'type' => 'select',
'multiple' => true,
'label' => $this->l('Branch Location'),
'name' => 'branch_location',
'required' => false,
'options' => array(
'query' => $list_branch_arr,
'id' => 'branch_location',
'name' => 'name'
),
'col' => '4',
'hint' => array(
$this->l('Please choose the branch name from the branch list.')
)
But no idea how to insert the selected values to database

You have to add the new field to the Customer Model.
/prestashop/classess/Customer.php
After
/** #var string Object last modification date */
public $date_upd;
add :
public $branch_location;
and modify :
public static $definition = array(
'table' => 'customer',
'primary' => 'id_customer',
'fields' => array(
'secure_key' => array('type' => self::TYPE_STRING, 'validate' => 'isMd5', 'copy_post' => false),
'lastname' => array('type' => self::TYPE_STRING, 'validate' => 'isName', 'required' => true, 'size' => 32),
'firstname' => array('type' => self::TYPE_STRING, 'validate' => 'isName', 'required' => true, 'size' => 32),
'email' => array('type' => self::TYPE_STRING, 'validate' => 'isEmail', 'required' => true, 'size' => 128),
'passwd' => array('type' => self::TYPE_STRING, 'validate' => 'isPasswd', 'required' => true, 'size' => 32),
'last_passwd_gen' => array('type' => self::TYPE_STRING, 'copy_post' => false),
'id_gender' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedId'),
'birthday' => array('type' => self::TYPE_DATE, 'validate' => 'isBirthDate'),
'newsletter' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool'),
'newsletter_date_add' => array('type' => self::TYPE_DATE,'copy_post' => false),
'ip_registration_newsletter' => array('type' => self::TYPE_STRING, 'copy_post' => false),
'optin' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool'),
'website' => array('type' => self::TYPE_STRING, 'validate' => 'isUrl'),
'company' => array('type' => self::TYPE_STRING, 'validate' => 'isGenericName'),
'siret' => array('type' => self::TYPE_STRING, 'validate' => 'isSiret'),
'ape' => array('type' => self::TYPE_STRING, 'validate' => 'isApe'),
'outstanding_allow_amount' => array('type' => self::TYPE_FLOAT, 'validate' => 'isFloat', 'copy_post' => false),
'show_public_prices' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool', 'copy_post' => false),
'id_risk' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedInt', 'copy_post' => false),
'max_payment_days' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedInt', 'copy_post' => false),
'active' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool', 'copy_post' => false),
'deleted' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool', 'copy_post' => false),
'note' => array('type' => self::TYPE_HTML, 'validate' => 'isCleanHtml', 'size' => 65000, 'copy_post' => false),
'is_guest' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool', 'copy_post' => false),
'id_shop' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedId', 'copy_post' => false),
'id_shop_group' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedId', 'copy_post' => false),
'id_default_group' => array('type' => self::TYPE_INT, 'copy_post' => false),
'id_lang' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedId', 'copy_post' => false),
'date_add' => array('type' => self::TYPE_DATE, 'validate' => 'isDate', 'copy_post' => false),
'date_upd' => array('type' => self::TYPE_DATE, 'validate' => 'isDate', 'copy_post' => false),
),
);
to :
public static $definition = array(
'table' => 'customer',
'primary' => 'id_customer',
'fields' => array(
'secure_key' => array('type' => self::TYPE_STRING, 'validate' => 'isMd5', 'copy_post' => false),
'lastname' => array('type' => self::TYPE_STRING, 'validate' => 'isName', 'required' => true, 'size' => 32),
'firstname' => array('type' => self::TYPE_STRING, 'validate' => 'isName', 'required' => true, 'size' => 32),
'email' => array('type' => self::TYPE_STRING, 'validate' => 'isEmail', 'required' => true, 'size' => 128),
'passwd' => array('type' => self::TYPE_STRING, 'validate' => 'isPasswd', 'required' => true, 'size' => 32),
'last_passwd_gen' => array('type' => self::TYPE_STRING, 'copy_post' => false),
'id_gender' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedId'),
'birthday' => array('type' => self::TYPE_DATE, 'validate' => 'isBirthDate'),
'newsletter' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool'),
'newsletter_date_add' => array('type' => self::TYPE_DATE,'copy_post' => false),
'ip_registration_newsletter' => array('type' => self::TYPE_STRING, 'copy_post' => false),
'optin' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool'),
'website' => array('type' => self::TYPE_STRING, 'validate' => 'isUrl'),
'company' => array('type' => self::TYPE_STRING, 'validate' => 'isGenericName'),
'siret' => array('type' => self::TYPE_STRING, 'validate' => 'isSiret'),
'ape' => array('type' => self::TYPE_STRING, 'validate' => 'isApe'),
'outstanding_allow_amount' => array('type' => self::TYPE_FLOAT, 'validate' => 'isFloat', 'copy_post' => false),
'show_public_prices' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool', 'copy_post' => false),
'id_risk' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedInt', 'copy_post' => false),
'max_payment_days' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedInt', 'copy_post' => false),
'active' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool', 'copy_post' => false),
'deleted' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool', 'copy_post' => false),
'note' => array('type' => self::TYPE_HTML, 'validate' => 'isCleanHtml', 'size' => 65000, 'copy_post' => false),
'is_guest' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool', 'copy_post' => false),
'id_shop' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedId', 'copy_post' => false),
'id_shop_group' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedId', 'copy_post' => false),
'id_default_group' => array('type' => self::TYPE_INT, 'copy_post' => false),
'id_lang' => array('type' => self::TYPE_INT, 'validate' => 'isUnsignedId', 'copy_post' => false),
'date_add' => array('type' => self::TYPE_DATE, 'validate' => 'isDate', 'copy_post' => false),
'date_upd' => array('type' => self::TYPE_DATE, 'validate' => 'isDate', 'copy_post' => false),
'branch_location' => array('type' => self::TYPE_INT),
),
);

the answer are not correctly .. due its not only dfined the field in the database, also must capture and stored in special way the values, in this example i demostrate to store as "1,2,3,6,8" using a single field
THE COMPLETE CODE AND ALL THE STEPS ARE AT: https://groups.google.com/forum/m/?hl=es#!topic/venenuxsarisari/z8vfPsvFFjk
here i put only the most important parts..
as mentioned int he previous link, added a new fiel in the model definition, class and the table sql
this method permits to stored in the db as "1,2,3" so you can use only a single field to relation that multiple selected values, a better could be using groupbox but its quite difficult, take a look to the AdminCustomers controller class in the controllers directory of the prestachop, this has a multiselect group that used a relational table event stored in single field
then in the helper form list array of inputs define a select as:
at the begining dont foget to added that line:
// aqui el truco de guardar el multiselect como una secuencia separada por comas, mejor es serializada pero bueh
$this->fields_value['id_employee[]'] = explode(',',$obj->id_employee);
this $obj are the representation of the loaded previous stored value when go to edit ... from that object, get the stored value of the field of your multiselect, stored as "1,3,4,6"
and the in the field form helper list of inputs define the select multiple as:
array(
'type' => 'select',
'label' => $this->l('Select and employee'),
'name' => 'id_employee_tech',
'required' => false,
'col' => '6',
'default_value' => (int)Tools::getValue('id_employee_tech'),
'options' => array(
'query' => Employee::getEmployees(true), // el true es que solo los que estan activos
'id' => 'id_employee',
'name' => 'firstname',
'default' => array(
'value' => '',
'label' => $this->l('ninguno')
)
)
),
an then override the post process too
public function postProcess()
{
if (Tools::isSubmit('submitTallerOrden'))
{
$_POST['id_employee'] = implode(',', Tools::getValue('id_employee'));
}
parent::postProcess();
}
this make stored in the db as "1,2,3"

Related

ZF2 Segment Route doesn't match parent's constraint when using children

I created the following routes:
'relatorios' => array(
'type' => 'Zend\Mvc\Router\Http\Segment',
'options' => array(
'route' => '/relatorios/:tipo',
'defaults' => array(
'controller' => 'Relatorios',
'action' => 'index',
'tipo' => 'normais',
),
'constraints' => array('tipo' => '(normais|administrativos)$',
),
'may_terminate' => true,
'child_routes' => array(
'view' => array(
'type' => 'Zend\Mvc\Router\Http\Segment',
'options' => array(
'route' => '/view/:id_relatorio',
'defaults' => array('action' => 'view'),
'constraints' => array('id_relatorio' => '[0-9]+'),
),
),
),
);
This is supposed to match the following routes:
/relatorios/normais //matches
/relatorios/administrativos //matches
/relatorios/normais/view/1 //doesn't match
/relatorios/administrativos/view/1 //doesn't match
So basically the :tipo parameter must be either normais or administrativos and there is a child /view/any_digits.
When the parent route is called it matches, when the child view is called it doesn't match because of my tipo constraint. Why is that?
As per my comment, the $ on the constraint means 'end of the string' (which in this case is the URL path), so it shouldn't be there.

Class was not found in the chain configured namespaces (zend framework 2 and doctrine 2)

I get the following error when I try to use an entity in my controller:
The class 'Application\Entity\User' was not found in the chain configured namespaces in C:\xampp\htdocs\zf2_pr6\vendor\doctrine\common\lib\Doctrine\Common\Persistence\Mapping\MappingException.php:37
My module.config.php configuration includes
'doctrine' => array(
'driver' => array(
'application_entities' => array(
'class' => 'Doctrine\ORM\Mapping\Driver\AnnotationDriver',
'cache' => 'array',
'paths' => array(__DIR__ . '/../src/Application/Entity')
),
),
'connection' => array(
'orm_default' => array(
'driverClass' => 'Doctrine\DBAL\Driver\PDOMysql\Driver',
'params' => array(
'host' => 'localhost',
'port' => '3306',
'user' => 'root',
'password' => '',
'dbname' => 'zf2',
),
),
),
),
'orm_default' => array(
'drivers' => array(
'Application\Entity' => 'application_entities',
),
),
I've also created a paste bin of other relevant files
Application\Entity\User
Application\Contorller\IndexController
How can I resolve this error add my driver to the chain of configured namespaces?
Your configuration is incorrect. At the moment you have the 'orm_default' config under the 'doctrine' key - Meaning the driver is never added to Doctrine.
You need to have the driver configuration and the 'orm_default' config sitting at the same level, under doctrine/driver.
'doctrine' => array(
'driver' => array(
'application_entities' => array(
'class' => 'Doctrine\ORM\Mapping\Driver\AnnotationDriver',
'cache' => 'array',
'paths' => array(__DIR__ . '/../src/Application/Entity')
),
'orm_default' => array(
'drivers' => array(
'Application\Entity' => 'application_entities',
),
),
)
),

zf2 regex routing

I am struggling with regex routing....
The following urls should be valid:
/shop/api/list
/shop/api/cart
/shop/api/login
/shop/api/details/0123456789
And the details url, the last one, is not really cooperating with the following route:
'child_routes' => array(
'angularlist' => array(
'type' => 'Regex',
'options' => array(
'regex' => '/api/(?<page>login|cart|list|details(?<id>\/[0-9]+))',
'spec' => '/api/%page%[/:%id%]',
'defaults' => array(
'__NAMESPACE__' => 'Shop\Controller',
'controller' => 'Api',
//'action' => '[a-zA-Z][a-zA-Z0-9_-]*',
'action' => 'list',
// 'param' => '[0-9]',
),
/* todo ipv elke child toe te voegen 'route' => '/api/[:action]', 'constraints' => array(
'action' => 'list|details|login|dashboard'
)*/
),
),
)
Instead of struggling with less-readable & dirty regex hacks, you can easily implement a Segment route stack like below:
'shop' => array(
'type' => 'Segment',
'options' => array(
'route' => '/shop/api',
'defaults' => array(
'__NAMESPACE__' => 'Shop\Controller',
'controller' => 'Api',
'action' => 'index'
),
),
'may_terminate' => true,
'child_routes' => array(
'angularlist' => array(
'type' => 'Segment',
'options' => array(
'route' => '/:action[/:id]', // id is optional
'constraints' => array(
'action' => '[a-zA-Z][a-zA-Z0-9_-]*',
'id' => '[0-9]+',
),
'defaults' => array(
'action' => 'index',
),
),
),
)

Zend Framework 2 child regex and literal routing

Based on this stackoverflow question 15077075 i have accomplished that my application has a regex based route so i can pass this to my view and edit action.
app/123 - app controller view action (get by article id)
app/name-of-article - app controller view action (get by article name)
app/123/edit - app controller edit action (article id)
app/name-of-article/edit - app controller edit action (article name)
app/search/{search-string} - app controler search action (currently only accepts a searchstring without spaces and special characters)
This i have accomplished with the code below and is similar to the code in the link above:
'app' => array(
'type' => 'literal',
'options' => array(
'route' => '/app',
'defaults' => array(
'controller' => 'App\Controller\App',
'action' => 'index',
),
),
'may_terminate' => true,
),
'view' => array(
'type' => 'regex',
'options' => array(
'regex' => '/app/(?<view>[a-zA-Z0-9_-]+)',
'defaults' => array(
'controller' => 'App\Controller\App',
'action' => 'view',
),
'spec' => '/app/%view%',
),
'priority' => -1000,
),
'edit' => array(
'type' => 'regex',
'options' => array(
'regex' => '/app/(?<view>[a-zA-Z0-9_-]+)/(?<edit>[a-zA-Z0-9_-]+)',
'defaults' => array(
'controller' => 'App\Controller\App',
'action' => 'edit',
),
'spec' => '/app/%view%/%edit%',
),
'priority' => -1000,
),
I have twoone issue
the first is that the url viewhelper doesn't recognize my routes
$controller = app
$action = recent
$this->url( $controller, array( 'action' => $action ) )
it just prints /app instead of /app/recent,
The same occurs when $action = 'search' or $action = 'new' it only prints /app
the second is that the search is recognized to its controller action only it fails when i put spaces or special characters in it
when i try to add \s in the constraints of the searchkey ( '[\sa-zA-Z0-9_-]+' ) it routes to the edit function
the route of search looks like this
Edited the route to this and it worked
'search' => array(
'type' => 'literal',
'options' => array(
'route' => '/app/search',
'defaults' => array(
'controller' => 'App\Controller\App',
'action' => 'search',
),
),
'may_terminate' => true,
'child_routes' => array(
'search' => array(
'type' => 'segment',
'options' => array(
'route' => '/[:searchkey]',
'constraints' => array(
'searchkey' => '[a-zA-Z0-9_\+-]+'
),
'defaults' => array(
'action' => 'search'
),
),
),
),
),
i hope it's clear what i want if any code snippits are needed please ask
Sorted it out!
If one needs to get routes in his application this way you can use the code below
/App App/Index
/App/name-of-article App/View
/App/123 App/View
/App/name-of-article/edit App/Edit
/App/123/edit App/Edit
/App/recent App/Recent
/App/search App/Search
/App/new App/New
In my module.config.php i changed the route to:
'app' => array(
'type' => 'segment',
'options' => array(
'route' => '/app[/:action]',
'constraints' => array(
'action' => '[a-zA-Z][a-zA-Z0-9_-]*',
'id' => '[0-9]+',
),
'defaults' => array(
'controller' => 'App\Controller\App',
'action' => 'index',
),
),
'may_terminate' => true,
),
'search' => array(
'type' => 'literal',
'options' => array(
'route' => '/app/search',
'defaults' => array(
'controller' => 'App\Controller\App',
'action' => 'search',
),
),
'priority' => 1,
'may_terminate' => true,
'child_routes' => array(
'search' => array(
'type' => 'segment',
'options' => array(
'route' => '/[:searchkey]',
'constraints' => array(
'searchkey' => '[\sa-zA-Z0-9_\+-]+'
),
'defaults' => array(
'action' => 'search'
),
),
'priority' => 2,
'may_terminate' => true,
),
),
),
'new' => array(
'type' => 'literal',
'options' => array(
'route' => '/app/new',
'defaults' => array(
'controller' => 'App',
'action' => 'recent',
),
),
'priority' => 2,
),
'view' => array(
'type' => 'regex',
'options' => array(
'regex' => '/app/(?<view>[a-zA-Z0-9_-]+)',
'defaults' => array(
'controller' => 'App\Controller\App',
'action' => 'view',
),
'spec' => '/app/%view%',
),
),
'edit' => array(
'type' => 'regex',
'options' => array(
'regex' => '/app/(?<view>[a-zA-Z0-9_-]+)/(?<edit>[a-zA-Z0-9_-]+)',
'defaults' => array(
'controller' => 'App\Controller\App',
'action' => 'edit',
),
'spec' => '/app/%view%/%edit%',
),
),
If you need other routes you can just add a new literal route below te app route, make sure you don't forget to set the priority

Search Through HABTM Checkbox/List

I have this contact form which also relates to a few other tables with a HABTM relationship. They are displayed in the form either as a list or as checkboxes. What I want is to be able to search through them while still in the form to select those that are applicable to the contact I am adding with the form. I'm not sure how to do this- was thinking maybe Javascript?
An example of what I am talking about is like Facebook when you're searching through your friends list.
Below are the HABTM relationships for the Contact Model:
public $hasAndBelongsToMany = array(
'Company' => array(
'className' => 'Company',
'joinTable' => 'companies_contacts',
'foreignKey' => 'contact_id',
'associationForeignKey' => 'company_id',
'unique' => 'keepExisting',
'dependent' => true,
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'finderQuery' => '',
'deleteQuery' => '',
'insertQuery' => ''
),
'Event' => array(
'className' => 'Event',
'joinTable' => 'contacts_events',
'foreignKey' => 'contact_id',
'associationForeignKey' => 'event_id',
'unique' => 'keepExisting',
'dependent' => true,
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'finderQuery' => '',
'deleteQuery' => '',
'insertQuery' => ''
),
'Screenoccupation' => array(
'className' => 'Screenoccupation',
'joinTable' => 'contacts_screenoccupations',
'foreignKey' => 'contact_id',
'associationForeignKey' => 'screenoccupation_id',
'unique' => 'keepExisting',
'dependent' => true,
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'finderQuery' => '',
'deleteQuery' => '',
'insertQuery' => ''
),
'Tapearchive' => array(
'className' => 'Tapearchive',
'joinTable' => 'contacts_tapearchives',
'foreignKey' => 'contact_id',
'associationForeignKey' => 'tapearchive_id',
'unique' => 'keepExisting',
'dependent' => true,
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'finderQuery' => '',
'deleteQuery' => '',
'insertQuery' => ''
),
'Relation' => array(
'className' => 'Contact',
'joinTable' => 'contacts_contacts',
'foreignKey' => 'contact_id',
'associationForeignKey' => 'related_id',
'unique' => true,
'conditions' => '',
'fields' => '',
'order' => '',
'limit' => '',
'offset' => '',
'finderQuery' => '',
'deleteQuery' => '',
'insertQuery' => ''
)
);
Not sure what other codes I need to show you guys, so please do let me know what codes are needed and I will add them to this question.
Thanks!
You could use a jquery plugin to do the job for you.
It seems that this one corresponds to your criteria. Chosen is nice too.
Anyway, do a google search to see all the jquery plugin available, and see if one fits your need.