ZF2: Populating select element in form with date from database - php

I have a database with a simple one-to-many relationship that looks like this:
Tables Company Category
Rows ID ID
Name Name
Category_ID
I have a forms where I can add, edit and delete the company's or category's name, which works fine. Entering the category by ID also works, but is obviously terrible to use. What I want is a simple select element in the form to pick from an existing category.
The code I have to generate the <select> is:
$this->add(array(
'name' => 'Categorie',
'type' => 'Zend\Form\Element\Select',
'attributes' => array(
'options' => $categories,
),
'options' => array(
'label' => 'Categorie',
),
));
From what I could find in the (extremely sparse) ZF2 documentation, I should be using a Hydrator to fetch data into the $categories variable, but I'm not sure where to go from there.
Any sort of example or tips would be well appreciated!

Here's a very good article about forms.
My solution is based on this tutorial and it is (almost) working well. I don't know if you use Doctrine for your project or not, but I think it would be a very good idea!
I also heavily use select elements. In the given fieldset, I generate value options for a select with this piece of code:
$opt= Registry::get('entityManager')->getRepository('My\Entity\Categories')
->getCategoriesForCombobox();
$this->get('category')->setValueOptions($opt);
If you (plan to) use Doctrine, you should read about repositories very carefully in the Doctrine documentation. If you use collections in the form, the topic about associations is also a must read.

Related

CakePHP Paginate Sort on Contain Data

It's a simple application for tracking user hobbies. A user can have many hobbies, which are organized into different hobby groups.
So I have 4 related tables: users, users_hobbies, hobbies, hobby_groups.
users is a has-and-belongs-to-many relation to hobbies, via the users_hobbies join table.
hobbies belongs-to a hobby_group, hobby_group has-many hobbies
Makes sense, pretty simple so far.
In UsersHobbiesController, I have:
$paginate = [
'contain' => [
'Hobby' => [
'fields' => ['id', 'name'],
'HobbyGroup' => [
'fields' => ['id', 'name']
]
]
]
];
Also, in my index() function, I build the pagination.
$usersHobbies = $this->paginate('UsersHobby');
$this->set(compact('usersHobbies));
When I access the $usersHobbies variable in my index.ctp View file, it has the data I want for building an output table. It looks like:
array(
(int) 0 => array(
'UsersHobby' => array(...),
'Hobby' => array(
'id' => 'abc-def-ghi',
'name' => 'Jet Skiing',
'HobbyGroup' => array(
'id' => 'oiuy-trew-qldf',
'name' => 'Watersports'
)
)
)
....
)
To sort the output table, I've added some sorting columns:
<th><?php echo $this->Paginator->sort('Hobby.name', 'Hobby'); ?></th>
<th><?php echo $this->Paginator->sort('Hobby.HobbyGroup.id', 'Hobby'); ?></th>
The first header works for sorting on the Hobby name. But I can't get the second header to sort for the HobbyGroup. Is there a simple way to do this?
I've searched for a few hours on StackOverflow, but can't seem to find an answer that works for me. Thanks.
This will not work as you expect because of how CakePHP fetches data.
Depending how you setup your relationships what will happen is that Cake will first select the Hobbies and then do another query for Hobby Groups.
So any sorting you apply to the second query will be generally useless and lost when that data is mapped to the list of Hobbies.
So you have
SELECT hobbies....
Then another select will be issued
SELECT hooby_groups WHERE hobby_id IN [list of ids ] ORDER BY hobby_groups_id
The data from the second select will be mapped to the first one, so your order by did not do much!
Depending on what CakePHP version you are using you can do a couple of things:
Define the relationship to use INNER JOIN strategy so will avoid creating two SELECT statements. This way the order by cause will sort all the data as you expect. The caveat is that with INNER JOIN Hobbies that do not have any group associated will never be selected by your pagination.
If you are using CakePHP 2.x you could have a look at Custom Query Pagination and build the query as you need it to be for it to work.
If you're using CakePHP 3.x you have a query builder there and the Paginator can paginate any query, so you can do you inner joins there.
To help you out you can use the DebugKit from CakePHP to see what actual queries are being run and how tweaking this and that parameter affects how the query is being generated. You will see where the order by is applied and why it may not work.
In CakePHP 2.x you can use type to control how the joining is done. You need to use INNER

Optimize query in Laravel Backpack n-n relationships

I am building a backend panel for a website with Laravel Backpack. It is really nice, but I have noticed that relationship queries are very expensive.
I have two models: Product and Center with a many to many relationship between them. In my CenterCrudController I have defined a field this way:
$this->crud->addColumns([
// More fields...
[
'label' => 'Products',
'type' => 'select2_multiple',
'name' => 'products', // the method that defines the relationship in your Model
'entity' => 'products', // the method that defines the relationship in your Model
'attribute' => 'name', // foreign key attribute that is shown to user
'model' => 'App\Models\Product', // foreign key model
'pivot' => true, // on create&update, do you need to add/delete pivot table entries?
],
// More fields...
]);
It works fine, showing a select multiple field with related models. But the query used is SELECT * FROM products, which is highly expensive (table products have thousands of records with about 25 columns).
In this example I only need id and name fields. I am looking for something like Query Builder select() method.
Is there a way for optimizing this type of query?
Thanks in advance!
Not sure if this is actually an answer, but I'll post it anyway.
The best solution (as pointed by #tabacitu) was using select2_from_ajax field. It doesn't slow page load and make an ajax request for retrieving data only when user clicks on the select field.

A best way to protect entity field in Symfony forms

In my Symfony2 app there are users end hotels, for each user it's esay to define his hotels.
In order to list user's hotels I use
class HotelVoter implements VoterInterface
which works fine.
In application there are forms of Order to a Hotel (so order.hotel_id = hotel.id). For this reason there is a field Hotel in Order's form:
$builder->add('hotel', 'entity', array(
'class' => 'AcmeHelloBundle:Hotel',
'property' => 'name',
'query_builder' => ...,
...
));
The problem is that form shows me all existing hotels regardless security voter.
What is the best way to leverage my existing voter. I don't feel like using query_builder for this aim.
Thanks

how to use drop down list of a cgrid view in yii?

Hi, I know this should be really simple but I am just too new to php and yii. So, please, bear with me. I have a table named thefriends which has columns(thepals,address,phone numbers). Now the admin page uses a CGridView to list all these friends in the usual format. I want the text boxes to be replaced by drop down menus. I know it can be done by using the following code in views/Thefriends/admin.php
'columns'=>array(
'id',
'array'(
'name'='thepals',
'filter'=array(1=>'alice',2=>'jenna'),
)
But as you see I have to populate the values myself, instead I want all the values to be prepopulated from the particular column.. please help..
Use a CHtml::ListData object as the filter. For instance, let's assume that your related thePals table has the columns id and name.
'columns' => array(
'id',
array(
'name' => 'thepals',
'filter' => CHtml::listData(thePals::model()->findAll(),'id','name'),
...
),

Building conditional statement across multiple models (CakePHP 1.2.5)

Let's say I have 3 models: User, Region, Country.
User belongsTo Region
Region belongsTo Country
Each of these models is using the Containable behavior. I'm attempting to find users from the country with code 'US'. Here's what I'm attempting:
$users = $this->User->find('all', array(
'conditions' => array('Country.code' => 'US'),
'contain' => array('Region.Country'),
));
CakePHP is separating this into 2 queries:
First, it is SELECTing the ID's for all countries with code 'US'.
Then it is using those ID's to SELECT all users JOINing regions where region.country_id is in that list of country ID's previously retrieved.
As a result, I end up with SQL errors in my app since my conditions array contains a reference to Country.code, and the second query that Cake builds doesn't JOIN countries.
The best Cake solution I see is to build a sub-query as described in the Complex Find Conditions portion of the manual. However, this seems very convoluted, and is more of a hack than I would like to implement. Is there an easier way that I'm overlooking?
Nate Abele (former lead dev of CakePHP) wrote an article about doing ad hoc joins which might help.
Put the conditions in the contain as well. E.g:
$users = $this->User->find('all', array('contain' => array(
'Region' => array(
'Country' => array(
'conditions' => array('Country.code' => 'US'),
),
),
)));
See the second-to-last example in the Containable manual

Categories