zend form dependent dropdown - forms

I have two dropdown in a form for selecting department and designation.
$model = new Application_Model_DbTable_Department();
$departments = $model->fetchAll();
$department = $this->createElement('select','department');
$department->setLabel('Department');
$department->setAttrib('class', 'department');
foreach($departments as $d)
$department->addMultiOption($d->id, $d->depname);
$model = new Application_Model_DbTable_Designation();
$designations = $model->fetchAll('depid=1');
$designation = $this->createElement('select','designation');
$designation->setLabel('Designation');
$designation->setAttrib('class', 'designation');
$designation->setRegisterInArrayValidator(false);
foreach($designations as $ds)
$designation->addMultiOption($ds->id, $ds->designation);
I have jquery function to for designation lookup when onchange of department. My problem is when submitting the form if the form has validation error , I need to display the selected designation.

In cases like this, It is best to do the form population after the form has been instantiated. Reason: it is next to impossible to get the values of the form elements on initialization because they do not exist yet (That is, in the init() method of the Zend_Form). You could do this:
$form = new Your_Zend_Form();
$designation = $form->getElement('designation');
$departmentId = null;
$request = $this->getRequest();
if($request->isPost()){
$departmentId = $request->getPost('department');
}
$desigantionOptions = $this->_getDesignationOptions($departmentId);
$designation->addMultiOptions($desigantionOptions);
This would be in your controller action or something... But in essence, your designation options would take values from the current department if available from the post or else it would fall to the default selection. The method signature of $this->_getDesignationOptions($departmentId) will be as follows:
protected function _getDesignationOptions($departmentId = null);
And this would return an array of value/option pair.

Related

Zend Paginate - find a specific record within the result

I appreciate that this may not be possible, but is there a way to make Zend Paginate go to a specific item (record)?
The result I would like would allow me to seek a specific record in a tabled list of results, and display the appropriate page (within all available pages) combined with a name anchor tag to display the specific record.
To clarify: If I had the results as a Zend_Db_Table_Rowset_Abstract I would use the seek() method in a similar fashion to $rowset->seek(8); Although I don't believe the result returned by the DbSelect adapter is a SeekableIterator?
The code within my Mapper (using the Table Data Gateway pattern):
public function paginate($where = array(), $order = null)
{
$select = $this->getDbTable()->select()->from($this->getTableName(), $this->getTableFields());
foreach ($where as $key => $value) {
$select->where($key, $value);
}
$select->order($order);
$adapter = new Zend_Paginator_Adapter_DbSelect($select);
$paginator = new Zend_Paginator($adapter);
return $paginator;
}
Within my controller:
$cache_id = sha1('list');
$mapper = new Application_Model_Galleries_Mapper();
if(!($data = Zend_Registry::get('cache')->load($cache_id))) {
$data = $mapper->paginate(array(), $sort);
Zend_Registry::get('cache')->save($data, $cache_id, array('list'), 7200);
}
$data->setCurrentPageNumber($this->_getParam('page'));
$data->setItemCountPerPage(30);
$this->view->paginator = $data;
To return a Zend_Paginator with a seekable iterator (Zend_Db_Table_Rowset) use the Zend_Paginator_Adapter_DbTableSelect() as it returns a rowset object, as opposed to Zend_Paginator_Adaoter_DbSelect() which returns an array().
Zend_Paginator

Need Help with Zend Form dropdown menu validation

I'm working on a zend framework project and I needed the user to select school and then it goes to the next form then select the grade.
Eg User select ABC High School and then select "Grade 8"
Both School and Grade dropdown menu is soft coded fetching the data from the database.
My problem is that when the user selected a school and then on the next grade form if they don't select any values and click onto "submit" it return a validation error "Value is required and can't be empty" which is correct but the dropdown menu then goes empty.
I wanted to know how to repopulate the values back to the grade dropdown menu if the form doesn't validate.
Thanks so much
Here is my code
Here is the function i generate the grade values (Fetching from the database)
public function processSchoolSelectionAction()
{
$form = $this->getSchoolSelectionForm();
if ($form->isValid($_POST))
{
// getting the values
$schoolId = $form->getValue('school');
$schoolYear = new Application_Model_DbTable_SchoolYear();
$schoolYearValues = $schoolYear->getYearValues($schoolId);
array_unshift($schoolYearValues, array ('key' =>'' , 'value' =>'Please Specify'));
$form = $this->getYearSelectionForm();
$form->year->addMultiOptions($schoolYearValues);
$form->schoolId->setValue($schoolId);
$this->view->form = $form;
}
else
{
$data = $form->getValues();
$form->populate($data);
$this->view->form = $form;
}
}
Code processing the year selection form
public function processYearSelectionAction()
{
$form = $this->getYearSelectionForm();
if ($form->isValid($_POST))
{
// getting the values
$schoolId = $form->getValue('schoolId');
$yearId = $form->getValue('year');
$textbookList = new Application_Model_DbTable_TextbookList();
if ($textbookList->checkTextbookExist($schoolId, $yearId))
{ // check if textbookExist
}
else
{
$this->view->message = "Sorry, But the list you requested is currently not available for ordering online.";
}
}
else
{
$data = $form->getValues();
$form->populate($data);
$this->view->form = $form;
}
}
School selection form
<?php
class Application_Form_SchoolSelection extends ZendX_JQuery_Form
{
public function init()
{
$this->setName('schoolSelection');
$school = new Application_Model_DbTable_School;
$schoolValues = $school->getSchoolValues();
array_unshift($schoolValues, array ('key' =>'' , 'value' =>'Please Specify'));
$schoolElement = new Zend_Form_Element_Select('school');
$schoolElement->addMultiOptions($schoolValues);
$schoolElement->setLabel('School');
$schoolElement->setRequired(true);
$schoolElement->setRegisterInArrayValidator(false);
$submitElement = new Zend_Form_Element_Submit('submit');
$submitElement->setLabel("Next");
$this->addElements(array(
$schoolElement,
$submitElement
));
}
}
?>
Grade (Year) selection form
<?php
class Application_Form_YearSelection extends ZendX_JQuery_Form
{
public function init()
{
$this->setName('yearSelection');
$yearElement = new Zend_Form_Element_Select('year');
$yearElement->setLabel('Year');
$yearElement->setRequired(true);
$yearElement->setRegisterInArrayValidator(false);
$schoolIdElement = new Zend_Form_Element_Hidden('schoolId');
$submitElement = new Zend_Form_Element_Submit('submit');
$submitElement->setLabel("Next");
$this->addElements(array(
$yearElement,
$schoolIdElement,
$submitElement
));
}
}
?>
This is how I done that:
In Controller when form is creating, pass data from request:
$some_selected_data = $this->_getParam('param_from_request'); // you need to validate this
$form = new Application_Form_SchoolSelection( array('some_data' => $some_selected_data) );
Then, in Form Class get that value like this:
$data = $this->getAttrib('some_data'); // the key value of array above
and just ask
if($data) {
// get value from DB and
//SET VALUE TO Zend_Form_Element
}
Obviously, you need to repopulate the options of your Select field.
In your processYearSelectionAction, on the validation failure part just grab the schoolId you stored in the hidden field and use it the same way as you did in your processSchoolSelectionAction to populate your field options.

Zend Dojo FilteringSelect from joined tables How can this be done with Doctrine

I have a number of FilteringSelect elements within my Zend Framework application that are working fine but they are based on simple queries.
I now need to create a FilteringSelect that will allow me to select the id of one table while displaying the text of field in a related table, i.e. I have two tables groomservices and groomprocedures which are related (i.e. groomprocedures.groomProceduresID has many groomservices.procedure).
The form I'm trying to create is for an appointments table which has many groomservices.groomServicesID values. I want the user to be able to see the name of the procedure while saving the value of the groomservices.groomServicesID using the FilteringSelect.
So far I've not been able to do this in that my FilteringSelect displays nothing, I'm sure this can be done just that the fault is with my inexperience with Zend,Doctrine and Dojo
I'm not sure if my problem is with my autocomplete action(including the query) or with the FilteringSelect element.
Can anyone spot where I've gone wrong in the code sections below, I need to get this working.
My autocomplete action within my controller
public function gserviceAction()
{
// disable layout and view rendering
$this->_helper->layout->disableLayout();
$this->getHelper('viewRenderer')->setNoRender(true);
// get a list of all grooming services IDs and related procedures
$qry= Doctrine_Query::create()
->select('g.groomServicesID,p.groomProcedure')
->from('PetManager_Model_Groomservices g')
->leftJoin('g.PetManager_Model_Groomprocedures p');
$result=$qry->fetchArray();
//generate and return JSON string
$data = new Zend_Dojo_Data('g.groomServicesID',$result);
echo $data->toJson();
}
My FilteringSelect element code
// Create a autocomplete select input for the service
$gservice = new Zend_Dojo_Form_Element_FilteringSelect('gapmtService');
$gservice->setLabel('Proceedure');
$gservice->setOptions(array(
'autocomplete' => true,
'storeID' => 'gserviceStore',
'storeType' => 'dojo.data.ItemFileReadStore',
'storeParams' => array('url' => "/groomappointments/appointment/gservice"),
'dijitParams' => array('searchAttr' => 'groomProcedure')))
->setRequired(true)
->addValidator('NotEmpty', true)
->addFilter('HTMLEntities')
->addFilter('StringToLower')
->addFilter('StringTrim');
Many thanks in advance,
Graham
P.S. orgot to mention I tried the following query in mysql and I gave me what I'm looking for I believe the Doctine query evaluates to the same.
select groomservices.groomservicesID,groomprocedures.groomprocedure from groomprocedures left join groomservices on groomprocedures.groomproceduresID =groomservices.groomProcedure
But I'm not sure if I formatted the query correctly in Doctrine.
EDIT in relation to the flammon's comments
Ok I've set the code to the following but I'm still not getting anything to display.
public function gserviceAction()
{
$ajaxContext = $this->_helper->getHelper('AjaxContext');
$ajaxContext->addActionContexts(array(
'gservice' => 'json'
));
// get a list of all grooming services IDs and related procedures
$qry= Doctrine_Query::create()
->select('g.groomServicesID AS id,p.groomprocedure AS name')
->from('PetManager_Model_Groomservices g')
->leftJoin('g.PetManager_Model_Groomprocedures p');
$this->view->model = (object) array();
$this->view->model->identifier = 'id';
$this->view->model->label = 'name';
$this->view->model->items = array();
$tableRows = $this->dbTable->fetchAll($qry);
foreach ($tableRows as $row) {
$this->view->model->items[] = $row->toArray();
}
}
I'm sure the fault lies with me.
It looks like there's a problem with the data that you're putting in the ItemFileReadStore.
Here are a few pointers.
Consider extending Zend_Rest_Controller for your services. It'll be easier to manage your contexts and your views. You'll be able to do something like this:
public function init()
{
$ajaxContext = $this->_helper->getHelper('AjaxContext');
$ajaxContext->addActionContexts(array(
'gservice' => 'json'
));
}
And it will eliminate the need for the following in each of you service actions.
// disable layout and view rendering
$this->_helper->layout->disableLayout();
$this->getHelper('viewRenderer')->setNoRender(true);
You'll need to either pass the format parameter or use the following plugin to help with the context switch. Passing the format parameter is simpler but it pollutes the url with ?format=json. Here's the Zend documentation on AjaxContext.
Here's a plugin that you can use if you don't want to pass the format parameter.
class Application_Plugin_AcceptHandler extends Zend_Controller_Plugin_Abstract
{
public function dispatchLoopStartup(Zend_Controller_Request_Abstract $request)
{
if (!$request instanceof Zend_Controller_Request_Http) {
return;
}
$header = $request->getHeader('Accept');
switch (true) {
case (strstr($header, 'application/json')):
Zend_Registry::get('logger')->log('Setting format to json', Zend_Log::INFO);
$request->setParam('format', 'json');
break;
case (strstr($header, 'application/xml')
&& (!strstr($header, 'html'))):
Zend_Registry::get('logger')->log('Setting format to xml', Zend_Log::INFO);
$request->setParam('format', 'xml');
break;
default:
Zend_Registry::get('logger')->log('Setting format to html', Zend_Log::INFO);
break;
}
}
}
In your controller, instead of echoing the data, create view variables that dojo expects. See this document for the format.
$this->view->model = (object) array();
$this->view->model->identifier = 'id';
$this->view->model->label = 'name';
$this->view->model->items = array();
In your controller, fetch your table rows:
$tableRows = $this->dbTable->fetchAll($select);
or, if you've put model code in a function, it might look more like:
$tableRows = $this->dbTable->fetchGroomProcedures();
Put your row data in the model->items[] array:
foreach ($tableRows as $row) {
$this->view->model->items[] = $row->toArray();
}
Create a view, view/scripts/appointment/gservice.json.phtml and in it put
Zend_Json::encode($this->model)
Use Firebug to see what is returned from your service.

Symfony: question about the form filters

In the frontend I have a page with a list and a form filter next to it
that shows all the users of a social network.
I would like to hide the user of the session in that list. How can I
do it?
My first thought is creating a function, addXXXXColumnQuery(), for each
field of the form, and in each one add a line like this:
->andWhere("u.id <> ?", $id)
$id being the ID of the user of the current session. But in that way I
find I'm repeating myself.
What should I do?
First, you need to get the user into the filter. You have two options:
Pass the user_id in as an option when you instantiate the form, inside the action:
public function executeList(sfWebRequest $request)
{
$user_id = $this->getUser()->getUserId();
$filter = new ModelFormFilter(array(), array('user_id' => $user_id));
...
Get the user id from the context inside of the form:
sfContext::getInstance()->getUser()->getUserId();
I prefer the former method because it's cleaner and less WTFy.
Once you have the user id, override doBuildQuery to exclude the current user id inside of your FormFilter:
protected function doBuildQuery(array $values)
{
$query = parent::doBuildQuery($values);
$user_id = $this->getOption('user_id'); //or off the context here
if ($user_id)
{
$query->addWhere('r.user_id != ?', $user_id);
}
return $query;
}

Drupal 6: Modifying uid of a submitted node

I have a situation where I want a set of users (employees) to be able to create a node, but to replace the uid (user ID) with that of the users profile currently displayed.
In other words, I have a block that that calls a form for a content type. If an employee (uid = 20) goes to a clients page (uid =105), and fills out the form, I want the uid associated with the form to be the client's(105), not the employee's.
I'm using arg(1) to grab the Client's uid - here is what I have..
<?php
function addSR_form_service_request_node_form_alter(&$form, $form_state) {
if (arg(0) == 'user' && is_numeric(arg(1))) {
$form['#submit'][] = 'addSR_submit_function';
}
}
function addSR_submit_function($form, $form_state) {
$account = user_load(arg(1));
$form_state['values']['uid'] = $account->uid;
$form_state['values']['name'] = $account->name;
}
?>
The form is loading in the block, but when submitted, is still showing the employee uid. I don't want to use hook_form_alter because I don't want to modify the actual form, because clients can fill out the form directly, in this case, I don't want to modify the form at all.
I'm also ashamed that I'm putting this in a block, but I couldn't think of a way to put this in a module, so any suggestions on that would also be appreciated...
To create your form in a block, you could use the formblock module. Especially if you are not used to use the Drupal API. Then all that's left if to add your own submit handler to the form. This is a piece of code that is run, when the form is submitted. You only want to do this on clients pages so you would do that using the hook_form_alter function.
/**
* Hooks are placed in your module and are named modulename_hookname().
* So if a made a module that I called pony (the folder would then be called
* pony and it would need a pony.info and pony.module file I would create this function
*/
function pony_form_service_request_node_form_alter(&$form, $form_state) {
// Only affect the form, if it is submitted on the client/id url
if (arg(0) == 'client' && is_numeric(arg(1))) {
$form['#submit'][] = 'pony_my_own_submit_function';
}
}
function pony_my_own_submit_function($form, &$form_state) {
$account = user_load(arg(1));
$form_state['values']['uid'] = $account->uid;
$form_state['values']['name'] = $account->name;
}
The idea behind this code, is to only alter the form when the condition is met - that it is submitted on a client page. I guessed that the arg(0) would be client so if it's something else you would need to change that of cause. We only need to add a submit function, since what we want is to change the values if the form has passed validation.
Then if that is the case our 2nd function is run, which does that actual alteration of the values.
PHP blocks are bad. You can put them in a module.
function hook_block($op, $delta = 0) {
// Fill in $op = 'list';
if ($op == 'view' && $delta = 'whatever') {
$account = user_load(arg(1));
$node = array('uid' => $account->uid, 'name' => $account->name, 'type' => 'service_request', 'language' => '', '_service_request_client' => $account->uid);
$output = drupal_get_form('service_request_node_form', $node);
// Return properly formatted array.
}
}
Additionally, you want a form_alter just to enforce the values. It's ugly but it works.
function hook_form_service_request_node_form_alter(&$form, $form_state) {
if (isset($form_state['node']['_service_request_client'])) {
$form['buttons']['submit']['#submit'] = array('yourmodule_node_form_submit', 'node_form_submit');
}
}
function yourmodule_node_form_submit($form, &$form_state) {
$account = user_load($form_state['node']['_service_request_cilent'])l
$form_state['values']['uid'] = $account->uid;
$form_state['values']['name'] = $account->name;
}