How to use same elements of same model in yii? - php

I am new to yii.. I am developing a form in which i am having a registration form in which i need to get education details of a student. It includes
'Post Graduation',
'Graduation' and
'Schooling'
details. Each of this will be having pass year, qualification etc fields.
public function attributeLabels()
{
return array(
'id' => 'ID',
'user_id' => 'User',
'qualification_id' => 'Qualification',
'specialization_id' => 'Specialization',
'pass_year' => 'Pass Year',
'university_id' => 'University',
'duration_from' => 'Duration From',
'duration_to' => 'Duration To',
'percentage_marks' => '% of Marks / GPA',
'course_type_id' => 'Course Type',
'awards' => 'Awards & Scholarships',
);
}
How can i use the same model to create similar elements to get these details separately for
'Post Graduation',
'Graduation' and
'Schooling'
I tried by creating different objects for the model and including them in the form.
$postGraduate = new CandidateQualification;
$graduate = new CandidateQualification;
$preGraduate = new CandidateQualification;
But this create problem as all of them will be having same name and validation also wont help. Please provide any solution.
Thanks in advance.

Use scenario`s Luke.
Scenarios are an extremely useful tool for separating validation tasks on any class you use derived from CModel. In this tutorial we will use CActiveRecord.

For this Specific task you need to use scenarios as others have mentioned.Understanding Scenarios. Once you have these defined in your model all you need is to create instance of classes with required scenario
for example you can do
$studentModel = new student('pregrad');
$studentModel = new student('grad');
$studentModel = new student('postgrad');
and when ever form is rendeded using same $studentModel validations would be different

Related

categoryChoiceTree in prestashop module configuration page

I'm developing a prestashop module and I'm trying to show a category tree in my backoffice configuration page.
I'm trying to follow this instructions below but I don't know exactly where to add this code.
It should be inside main module's php? or inside a separate .php file and call it from the main one (don't know how to do it either).
As much time I'm spending trying to figure out, how to implement the code in the link above, the more I think I'm losing my time.
I see that "use" files, and this JS, " /admin-dev/themes/new-theme/js/components/form/choice-tree.js " are not in any prestashop folders.
Well, you should invest some time and learn Symfony since this is what you need to build backend modules for Prestashop 1.7.
As a pointer, you need to create a form class extending the CommonAbstractType, add a build form method. e.g. :
public function buildForm(FormBuilderInterface $builder, array $options)
{
$this->context = Context::getContext();
$parents = [
['id_category' => 2, 'name' => 'Home', 'children' => $this->getSubCategories(1, true, 2)]
];
$builder->add('category', CategoryChoiceTreeType::class, [
'choices_tree' => $parents,
'choice_value' => 'id_category',
'choice_children' => 'children',
'choice_label' => 'name',
'disabled_values' => $disabledCategories,
'label' => 'Choose a category'
])
then add methods for retrieving the data to populate the form fields.
Then use this class in your controller and display the form:
$form = $this->createForm(YourFormForm::class);
Also add a processForm to process data.
As mentioned, this is not a copy/paste situation you need to understand the Symfony workflow.
The only way that I found to "paint" the categorytree in my configuration page is adding this code to the inputs form array:
Can anyone tell me how to retrieve users selection data to my database?
It does not work as any other form field.
array(
'type' => 'categories',
'label' => $this->l('Destination Category'),
'desc' => $this->l('Select ONE Category'),
'name' => 'CATEGORY_CATEGORY_TO',
'tree' => [
// 'selected_categories' => [],
'disabled_categories' => null,
'use_search' => false,
'use_checkbox' => false,
'id' => 'id_category_tree',
],
'required' => true
),
Well, it is SOLVED!!!! Finally it was very simple, but you must get the correct info for you particular case.
#Robertino's answer might be the best implementation, I don't know, but it became impossible to solve for me,
I uses this code below, and called $categoryTree from the form input. This input must be type=> categories_select
Thanks for your time, and for the help of another post from this forum.
$root = Category::getRootCategory();
//Generating the tree
$tree = new HelperTreeCategories('categories_1'); //The string in param is the ID used by the generated tree
$tree->setUseCheckBox(false)
->setAttribute('is_category_filter', $root->id)
->setRootCategory($root->id)
->setSelectedCategories(array((int)Configuration::get('CATEGORY_1'))) //if you wanted to be pre-carged
->setInputName('CATEGORY_1'); //Set the name of input. The option "name" of $fields_form doesn't seem to work with "categories_select" type
$categoryTree = $tree->render();
And the Form:
array(
'type' => 'categories_select',
'label' => $this->l('Category'),
'desc' => $this->l('Select Category '),
'name' => 'CATEGORY_1', //No ho podem treure si no, no passa la variable al configuration
'category_tree' => $categoryTree, //This is the category_tree called in form.tpl
'required' => true

PrestaShop: Saving Manufacturers

I asked this same question on the official forums but received no response. Not sure if anyone here is experienced with PrestaShop but here is my issue.
I need to add an extra field in the manufacturer edit/add tab, I was able to do this by overriding renderForm in AdminManufacturersController.php like this:
public function renderForm()
{
global $shopOptions;
$this->fields_form_override = array(
array(
'type' => 'checkbox',
'label' => 'Shop',
'name' => 'shop_select',
'desc' => 'Choose The Shops This Manufacturer Applies To',
'values' => array(
'query' => $shopOptions, >> comes from array filled by db query in __construct
'id' => 'id',
'name' => 'name'
),
),
);
return parent::renderForm();
}
This works and I am now trying to find the update and create functions for a manufacturer. When editing the product classes, you can easily spot set functions like setQuantity in StockAvailable.php.
I have ssh access to the server so I was able to dig deeper with grep, to no avail. It seems like it uses some sort of function to auto insert into the database whilst some classes use a plain old execute with a normal query.
Any ideas on where this could be found?
On Prestashop 1.6.x you do not need to amend any function for it to have CRUD functionalities. You just need to add it in :
RenderForm (like you already did)
Add the variable in the manufacturer class (Manufacturer.php) like public $shop_select;
Add it in the public static $definition array in the manufacturer class
Add the column in manufacturer or manufacturer_lang table depending on whether your field is a lang field.
Cheers :)

association count within selection

I have a Candidate doctrine entity, this entity has a many to many association to a entity Group
On the index page i show all candidates.
Now i made a form with a ObjectMultiCheckbox object for the Group entity.
After selecting a checkbox and submitting the form i use the doctrine QueryBuilder to only show the candidates that have a association with the selected entity.
This works fine but in the form i'd like to show how many candidates are associated with a certain group.
I can do this using the label_generator option in ObjectMultiSelectCheckbox definition in the fieldset:
namespace MeCandidate\Form;
use Zend\Form\Fieldset;
use Zend\InputFilter\InputFilterProviderInterface;
class SearchFieldset extends Fieldset implements InputFilterProviderInterface
{
public function __construct($objectManager)
{
parent::__construct($name = 'search');
$this->add(
array(
'type' => 'DoctrineModule\Form\Element\ObjectMultiCheckbox',
'name' => 'function',
'attributes' => array(
'class' => 'searchCriteria'
),
'options' => array(
'label' => 'Group',
'object_manager' => $objectManager,
'target_class' => 'MeCandidate\Entity\Group',
'label_generator' => function($targetEntity) {
return ' ' . $targetEntity->getName() . '('. $targetEntity->getCandidates()->count() .')';
},
),
)
);
}
public function getInputFilterSpecification()
{
return array(
array(
'name' => 'group',
'required' => false,
),
);
}
}
This all works as expected.
So when i select Group X it shows all candidates that have a association with Group X.
But now that only a selection of all candidates is shown the number of candidates associated with a certain group is no longer accurate as this shows the total number of candidates associated with the group but i need the number of candidates associated with the group IN the current selection.
I think i can fix it by injecting the current QueryBuilder into the form when creating the form. However i can't find a good way to get the right count.
I hope what i'm trying to do is clear, if not ask me anything.
UPDATE:
I have a working solution, in my Group entity i have a method getCandidateCount it takes a ArrayCollection of the current selection of candidates and checks if a associated candidate is in the selection. I adapted the label_generator function in the fieldset to call getCandidateCount
The problem with this is that after validating the form i have to recreate the form and inject the current selection of candidates into it so i can pass it to the getCandidateCount method inside the label_generator function.
It works but not very elegant so if anybody has ideas about how to it better i would love to hear them!
Thanks,
Yoram

How can I share validation arrays between models?

For example, I have several models that have name and uid fields but some models do not have them. I want all models that have those fields to use the following rules, however, I don't want to add the following block of code to each model.
public $validate = array(
'name' => array(
array(
'rule' => array('between', 1, 25),
'message' => 'Name must contain %d to %d characters',
'required' => true
),
array(
'rule' => array('custom', AppModel::REGEX_NAME),
'message' => 'Name contains invalid characters.'
)
),
'uid' => array(
'rule' => 'uuid',
'message' => 'uid is not valid.',
'required' => true
),
);
I've considered adding the rules to AppModel by setting public $validate. This leads to the following problems.
Models without those fields always fail validation because required is true.
If you set public $validate in a model, it will not inherit the rules from AppModel.
I'm sure this can be handled by adding validation on-the-fly (I'm thinking beforeValidate() in AppModel) but I would like to know how others are handling this.
Does anyone know a better way?
Personally I would just copy/paste the validation array in each model.
If that isn't what you want to do, you could do something like extend AppModel to MyAppModel. Within MyAppModel set public $validate = array(...), and for the models needing those validation rules simply extend MyAppModel instead of AppModel in your class declaration.
As for problem #2, you need to call parent::validate to retrieve that array and then supplement it with further rules. My initial thought would be to create an array for the new rules not found in MyAppModel and then array_merge with that array + parent::validate.
This is usually handled by just copy/pasting the validation array or setting up your "normal" validation rules into your bake template. That way, they're there by default upon starting each project.
Or per the comment above, you can use a Behavior - though unless you have a LOT of models, personally, I think that's overkill.
You could add a method like mergeDefaultRules() to your AppModel that can be called from
within each models beforeValidate() that merges the default rules
with the model specific rules
You could use traits instead of using an AppModel method for that - if you can use php 5.4
You could use a behavior
I would go for 1 or 2.
// In your AppModel
public function mergeDefaultRules() {
$this->validate = array_merge($this->validate, array(/* Default rules here */));
}
// In your specific model
public function beforeValidate($options = array()) {
$this->mergeDefaultRules();
return true;
}

Zend Form Edit and Zend_Validate_Db_NoRecordExists

I am slowly building up my Zend skills by building some utility websites for my own use. I have been using Zend Forms and Form validation and so far have been happy that I have been understanding the Zend way of doing things. However I am a bit confused with how to use Zend_Validate_Db_NoRecordExists() in the context of an edit form and a field that maps to database column that has to be unique.
For example using this simple table
TABLE Test
(
ID INT AUTO_INCREMENT,
Data INT UNIQUE
);
If I was simply adding a new row to the Table Test, I could add a validator to the Zend Form element for the Data field as such:
$data = new Zend_Form_Element_Text('Data');
$data->addValidator( new Zend_Validate_Db_NoRecordExists('Test', 'Data') )
At form validation this validator will check that the contents of the Data element does not already exist in the table. Thus the insert into Test can go ahead without violating the Data fields UNIQUE qualifier.
However the situation is different when editing an existing row of the Test table. In that case the validator needs to check that the element value meets one of two mutually exclusive conditions conditions:
The user has changed the element value, and the new value does not currently
exist in the table.
The user has Not changed the element value. Thus the value does currently exist in the table (and this is OK).
The Zend Validation Docs talk about adding a parameter to the NoRecordExists() validator for the purpose of excluding records from the validation process. The idea being to "validate the table looking for any matching rows, but ignore any hits where the a field has this specific value". Such a use case is what is needed for the validating the element when editing a table. The pseudo code to do this in 1.9 is like so (actually I got this from the 1.9 source code - I think the current docs may be wrong):
$data = new Zend_Form_Element_Text('Data');
$data->addValidator( new Zend_Validate_Db_NoRecordExists('Test', 'Data',
array ('field'=>'Data', 'Value'=> $Value) );
The problem is that the value that is to be excluded ($Value) is bound to the validator at the time it is instantiated (also when the form is instantiated). But when the form is editing a record, that value needs to be bound to the contents of the $data field when the form was initially populated with data - IE the Data value initially read from the Test table row. But in typical Zend patterns a form is instantiated and populated in two separate steps which precludes binding the exclude value to the desired element value.
The following Zend psuedo code marks where I would like the binding of $Value to the NoRecordExists() validator to occur (and note that this is a common Zend controller pattern):
$form = new Form()
if (is Post) {
$formData = GetPostData()
if ($form->isValid($formData)) {
Update Table with $formData
Redirect out of here
} else {
$form->populate($formData)
}
} else {
$RowData = Get Data from Table
$form->populate($RowData) <=== This is where I want ('value' => $Value) bound
}
I could sub-class Zend_Form and override the populate() method to do a one-shot insertion of the NoRecordExists() validator on initial form population, but that seems like a huge hack to me. So I wanted to know what other people think and is there some pattern already written down that solves this problem?
Edit 2009-02-04
I've been thinking that the only decent solution to this problem is to write a custom validator and forget about the Zend version. My form has the record ID as hidden field, so that given the table and column names I could craft some SQL to test for uniqueness and exclude the row with an ID of such an such. Of course this started me thinking about how I would be tying the form to the dB layer that the Model is supposed to hide!
This is how it's done:
I your FORM, you add this validator (for example email field):
$email->addValidator('Db_NoRecordExists', true, array('table' => 'user', 'field' => 'email'));
Don't add custom error message for this since after that it didn't work for me, e.g.:
$email->getValidator('Db_NoRecordExists')->setMessage('This email is already registered.');
In your Controller add this:
/* Don't check for Db_NoRecordExists if editing the same field */
$form->getElement('email')
->addValidator('Db_NoRecordExists',
false,
array('table' => 'user',
'field' => 'email',
'exclude' => array ('field' => 'id', 'value' => $this->request->get('id'))));
And after this you do verifications, e.g.:
if ($this->getRequest()->isPost())
{
if($form->isValid($this->getRequest()->getPost()))
{
....
That's it!
This will also work :
$this->addElement('text', 'email', array(
'label' => 'Your email address:',
'required' => true,
'filters' => array('StringTrim'),
'validators' => array(
'EmailAddress',
array('Db_NoRecordExists', true, array(
'table' => 'guestbook',
'field' => 'email',
'messages' => array(
'recordFound' => 'Email already taken'
)
)
)
)
));
After reviewing the overwhelming response I've decided that I'm going with a custom validator
Look at this one:
Answer raised by me and well-solved by Dickie
private $_id;
public function setId($id=null)
{
$this->_id=$id;
}
public function init()
{
.....
if(isset($this->_id)){
$email->addValidator('Db_NoRecordExists', false, array('table' => 'user', 'field' => 'email','exclude' => array ('field' => 'id', 'value' => $this->_id) ));
$email->getValidator('Db_NoRecordExists')->setMessage('This email is already registered.');
}
Now u can use:
$form = new Form_Test(array('id'=>$id));
You could just call $form->getElement('input')->removeValidator('Zend_Validator_Db_NoRecordExists'); instead of supplying the exclusion.
I have just tried this example for email address uniqueness and it works perfectly with below stuffs :
1] In my form:
// Add an email element
$this->addElement('text', 'email', array(
'label' => 'Email :',
'required' => true,
'filters' => array('StringTrim'),
'validators' => array(
'EmailAddress',
)
));
Here's something special that I needed to add for unique email address to work:
$email = new Zend_Form_Element_Text('email');
$email->addValidator('Db_NoRecordExists', true, array('table' => 'guestbook', 'field' => 'email'));
2] In my controller:
$form->getElement('email')
->addValidator('Db_NoRecordExists',
false,
array('table' => 'guestbook',
'field' => 'email',
'exclude' => array ('field' => 'id', 'value' => $request->get('id'))));
if ($this->getRequest()->isPost()) {
if ($form->isValid($request->getPost())) {
Hope it helps you people !
Thanks

Categories