Zend_Form display forms from DB table rows - zend-framework

I'd like to build a dynamic FORM according to DB Table records.
It'a room reservation module.
Hotel has several room types with descriptions.
When booking a hotel user should see form like:
-- firstname [text-input]
-- lastname [text-input]
-- check-in [text-input and datepicker]
-- check-out [text-input and datepicker]
-- Room1 Title:Room Description [Text-input form for number of rooms]
-- Room2 Title:Room Description [Text-input form for number of rooms]
-- Room3 Title:Room Description [Text-input form for number of rooms]
-- Room4 Title:Room Description [Text-input form for number of rooms]
I have this Room records in a table.
How can I build this with ZEND_FORM?
I think it should be smth like foreach of objects of rooms
I also would like to add auto calculations.
Each room has specific price per night.
I want to sum-up number of rooms and multiply by number of nights.
So how can I accomplish it using Zend_Form?
Should I add some helpers? new type of text element?
If yes, please provide some sources to guide's and How To's with examples.
Thank you in advance.

I had something similar but with checkboxes, this is an adaptation, I hope it helps.
class Form_Booking extends Zend_Form {
function init()
{
$this->addElement('text', 'first_name', array (
'label' => 'First name',
'required' => true
));
// ... all the other fields
$count = 1000; // I used this value because I had a strange bug
//$rooms = array() the entries from your table
foreach ($rooms as $one)
{
$this->addElement('checkbox', "$count", array (
'label' => $one['room_title'],
'description' => $one['room_description'],
'belongsTo' => 'rooms',
));
$count++;
}
}
}

Related

Get only few records depend on condition in collection of forms in Symony 2+

I have two table say Project and Project allocation.
If we create form of Project object we can also get all project allocation by default.
class projectType extends AbstractType {
......
->add('projectAllocation', 'collection',
array(
'type' => new \ProjectBundle\Form\Type\projectAllocationType(),
'allow_add' => true, 'allow_delete' => true,
'prototype' => true,))
...
Simlarly we have projectAllocationType form.
Now in this case all project allocation records will be retrieved in the form.
Can we have something like project allocation record which satisfy few condition like between some date etc.
Basically it is like search and edit if we have lot of collection record
Any suggestion will be helpful to implement same.
Edited
$qb=$repository->createQueryBuilder("p")
//->from('Project', 'p')
->leftJoin('p.billingItems', 'b')
->leftJoin('b.invoice', 'inv')
->where('p.projectId = ?1')
->orderBy('p.name', 'ASC')
->setParameter(1, $projectId);
if($invoice){
$qb->andWhere('inv.invoiceId='.$invoice);
// $queryString .= "and inv.invoiceId=".$invoice;
}
$query->getSql() query is proper.
SELECT p0_.project_id AS project_id0, p0_.name AS name1, b1_.billing_items_id
FROM project p0_
LEFT JOIN billing_items b1_ ON p0_.project_id = b1_.project_id
LEFT JOIN invoice i2_ ON b1_.invoice_id = i2_.invoice_id
WHERE p0_.project_id =171
AND i2_.invoice_id =3
ORDER BY p0_.name ASC
LIMIT 0 , 30
Here billing_items_id manually added while directly executing query on DB which displayed proper result.
But Doctrine query project object contains all billing items. I need only items which equal to invoice.
Adding ->select('p,b') solved my problem. To consider both entity data we have to include both entity reference.
$qb=$repository->createQueryBuilder("p")
->select('p,b')
->leftJoin('p.billingItems', 'b')
->leftJoin('b.invoice', 'inv')
->where('p.projectId = ?1')
->orderBy('p.name', 'ASC')
->setParameter(1, $projectId);
if($invoice){
$qb->andWhere('inv.invoiceId='.$invoice);
}

A set of fields for one property entity in Symfony 2

My Product entity has the following structure:
private $id;
private $title;
/**
* #ManyToOne(targetEntity="Category")
* #JoinColumn(name="cat_id", referencedColumnName="id")
*/
private $category;
Category have nested structure. And each level of nesting is shown in 5 separate fields:
In class form code, I solve it in this way:
$builder
->add('cat_1', 'entity', array(
...
'query_builder' => function() { return someSelectLogic1(); }
))
->add('cat_2', 'entity', array(
...
'query_builder' => function() { return someSelectLogic2(); }
))
->add('cat_3', 'entity', array(
...
'query_builder' => function() { return someSelectLogic3(); }
))
->add('cat_4', 'entity', array(
...
'query_builder' => function() { return someSelectLogic4(); }
))
->add('cat_5', 'entity', array(
...
'query_builder' => function() { return someSelectLogic5(); }
))
Now I need to know which field is filled in the last turn and pass the value of that field in the entity property.
In all that I do not like:
complex logic to determine which field with category was filled at the end
each of these fields is not tied to the entity 'mapped' => false
1) What the right way to organize code of my form?
2) And is there a way to bring these fields into a separate class which will deal with the logic of determining which category was chosen in the end?
I would suggest the following:
1) Create a new custom form field type and put all those entity in there.
This process is not much different from ordinary creation of form type. Just enclose those fields in it's own buildForm() and that should do the trick. Docs.
2) Mark all those entity fields with property "property_path => false".
Clearly you wont be storing these values inside your model.
3) Add two more fields: chosen and lastOne.
Now, this might be tricky: I would either set the chosen to text type (basically, generic type) or would use entity as well. If you go for entity you would need to include all possible answers from all entity fields. As for the lastOne set it to text as it will reflect which field (by name) was selected last.
Either way, those two fields will be invisible. Don't forget to set property_path to false for lastOne field.
4) Finally, add ValueTransformer (docs) which will contain logic to "see" which field was selected last.
Now, I dealt with it only once and don't understand it just quite yet, so your best bet would be trial and error with examples from official docs, unfortunately.
What basically you should do is to, within value-transformer, read the value of field lastOne. This will give you the name of field which was selected last. Then, using that value, read the actual last value selected. Last, set that value (object, if you've went for entity type, or it's ID otherwise) to chosen field.
That should basically do the thing.
As for the JS, I don't know if you're using any framework but I will assume jQuery. You will need to set lastOne field as your selecting items in your form.
$(function(){
$('#myform').find('select').on('change', function(){
var $this = $(this);
$this.closest('form').find('#__ID_OF_YOUR_LASTONE_FIELD').val($this.attr('name'));
});
});
I'm sorry I cannot provide you with code samples for PHP right now. It's a bit late here and will do my best to further update this answer tomorrow.

Entity mapping in a Symfony2 choice field with optgroup

Suppose to have an entity in Symfony2 that has a field bestfriend, which is a User entity selected from a list of User entities that satisfy a complex requirement.
You can render this field in a form by specifying that it is an entity field type, i.e.:
$builder->add('bestfriend', 'entity', array(
'class' => 'AcmeHelloBundle:User',
'property' => 'username',
));
This form field is rendered as a <select>, where each one of the displayed values is in the form:
<option value="user_id">user_username</option>
So, one would render the field by using the <optgroup> tags to highlight such special feature of the friends.
Following this principle, I created a field type, namely FriendType, that creates the array of choices as in this answer, which is rendered as follows:
$builder->add('bestfriend', new FriendType(...));
The FriendType class creates a <select> organized with the same <option>s but organized under <optgroup>s.
Here I come to the problem! When submitting the form, the framework recognize that the user field is not an instance of User, but it is an integer. How can I let Symfony2 understand that the passed int is the id of an entity of type User?
Here follows my solution.
Notice that it is not mentioned in the Symfony2 official docs, but it works! I exploited the fact that the entity field type is child of choice.
Hence, you can just pass the array of choices as a param.
$builder->add('bestfriend', 'entity', array(
'class' => 'AcmeHelloBundle:User',
'choices' => $this->getArrayOfEntities()
));
where the function getArrayOfEntities() is a function that fills the choice list with the friends of my friends, organized by my friends:
private function getArrayOfEntities(){
$repo = $this->em->getRepository('AcmeHelloBundle:User');
$friends = $repo->findAllFriendByComplexCriteria(...);
$list = array();
foreach($friends as $friend){
$name = $friend->getUsername();
if(count($friend->getFriends())>0){
$list[$name] = array();
foreach($friend->getFriends() as $ff){
$list[$name][$ff->getUsername()] = $ff;
}
}
}
return $list;
}
I know the example could be meaningless, but it works...
PS: You need to pass the entity manager to let it working...

Selecting multiple checking boxes with FormHelper in CakePHP

So in an Index view for a certain model, I'm including some checkboxes; I have an array of days of the week, and so have 7 checkboxes available, per record.
I can save data, no problem. What I can't figure out is how to pre-select the checkboxes, based on each record's saved data. Currently I'm having to do this:
<?php if ( isset($user['SurveyAssignment'][0]['active_days']['Monday']) && $user['SurveyAssignment'][0]['active_days']['Monday'] == 1 ) { $monChecked = true; } else { $monChecked = false; } ?>
<?php echo $this->Form->input('SurveyAssignment.' . $count .'.active_days.Monday', array('type' => 'checkbox', 'label' => false, 'div' => false, 'checked' => $monChecked));?>
And that's just for ONE day, for one record. Right now, I'm doing that 7 times, for each record. It's very bloated.
I would have thought I could just read in the array for each record, and select a group of checkboxes accordingly.
I'm sure I'm missing something very simple but I can't see past my nose at the moment.
If your associations are set up correctly, your field name is correct, and you're passing the correct data, they will be selected automatically for you.
The likely answer is you're not using the correct field or Model.field for your form input.

Typo3 foreign_table & foreign_table_where in TCA

I am struggling with the following problem.
I have two database tables, "Books" and "Category". I am getting all the data from "books"-table via Sysfolder in Backends List-view for editing, sorting and controlling them.
What I would like to get, is that there would be in that list view also the name of the category where the book belongs.
In "Books"-table there is a field foreign-key "category_id" which defines that for which category the Book belongs. I have tried via this "category_id" to get the name of the Category in List-view of the Books.
When I define in TCA['books'] that category_id like:
'category_id' => array (
'exclude' => 0,
'label' => 'Cat name',
'config' => array (
'type' => 'select',
'foreign_table' => 'category',
'foreign_table_where' => 'AND category.id=###REC_FIELD_category_id###',
'eval' => 'int',
'checkbox' => '0',
'default' => 0
)
),
it connects the Books and Categories using category_id (in Books-table) and uid (in Category-table).
Not like I would like, that it would connect them using category_id(in Books-table) and id(in Category-table). This id is a id of the category and can be different that uid.
Am I doing something wrong or does Typo3 somehow automatically makes this "connection" to foreign tables uid. ? Is there some way to get it like I would like?
I'm afraid it's not possible to specify different foreign key. So unless somebody proves me wrong, here is a workaround that I would use.
itemsProcFunc of the select type allows you to completely override the items in the menu and thus create a different relation.
Create an extra class that will be loaded in the backend only and that will have the method that will be called in the itemsProcFunc:
yourMethod($PA, $fobj)
Make the method to load all the categories you want to have in the SELECT box and set them in the $PA['items'] by completely overriding it so that it is an array of arrays where the 0 key is element title and 1 key is the category ID that you want. See items in select.
$PA['items'] = array(array($title, $id, ''));
Include the class in the ext_tables.php:
if(TYPO3_MODE == 'BE') require_once(t3lib_extMgm::extPath($_EXTKEY).'class.YOUR_CLASS.php');
Set the config for the category field in the books table:
'itemsProcFunc' => 'tx_YOUR_CLASS->yourMethod',
In addition to the great answer of cascaval:
#cascaval: Do you mind pointing to the select.items in the Typo3TCA in the select links? The current links aren't straight forward.
http://docs.typo3.org/typo3cms/TCAReference/singlehtml/#columns-select-properties-items
(no permission to comment to your answer, so had to answer myself just for this link ... weird)