CakePHP hasAndBelongsToMany Checkbox matrix - php

I have two models, Component and Group. A Group has many Components, and a Component can be in many Groups. Now, what I need is a view, in which there's a table, n times m field (or matrix) of checkboxes. The Columns would be all the Groups (which would be fewer) and the rows would represent the Component. Basically, when the HaBTM-Relationship exists, the checkbox is checked.
This should be editable, meaning it would be wrapped in a form.
| Group 1 | Group 2 | Group 3
C1 | x | | x
C2 | x | x |
C3 | | | x
What is the least stressful way to achieve this in CakePHP?

Alright.
First of course you load the data from your connecting table. So you get a lot of datasets like:
id => 4
component_id => 4
group_id =>3
Then you have an array of all existing components and another one which contains all existing groups.
Since you have the components in rows I would reorganise this array of arrays, so that you have a multidimensional array which as first key has the component_id and under this id you have an array containing the arrays of all datasets, which contain this group.
e.g.:
array(
1 => array(
0 => array(
'id' => 4,
'component_id' => 1,
'group_id' => 2,
),
1 => array(
'id' => 4,
'component_id' => 1,
'group_id' => 5,
),
),
2 => array(
0 => array(
'id' => 4,
'component_id' => 2,
'group_id' => 1,
),
1 => array(
'id' => 4,
'component_id' => 2,
'group_id' => 3,
),
),
);
After this reorganisation you can pass it to the view, where you can iterate through it to build the form, giving each checkbox the component-group info, which you can collect after sending the form.
Nicer than that (as a version 1.2) would be a AJAX call which saves the combination immediately after activating or deactivating the checkbox. Your choice ;)
Calamity Jane

Related

mysql pattern select based on values

I cant think up some good solution. My database structure is:
id name
----------
9 beer
10 beer {cold}
11 beer {hot}
12 juice
13 juice {orange}
14 juice {green}
15 juice {black}
I need select so possible output to have:
- one row of main product
- and all same products containing any text between characters {%} will be an alternatives of main product.
I need this output: (2 rows with alternatives -- but no 7 rows)
array(
array(
id => 9,
name => beer,
alternatives => array (
array(
id => 10,
name => cold
),
array(
id => 11,
name => hot
)
)
),
array(
id => 12,
name => juice
alternatives => array (
array(
id => 13,
name => orange
),
array(
id => 14,
name => green
),
array(
id => 15,
name => black
)
)
)
);
Do you think, is this possible with ONE Query?

PHP MySQL Menu Sorting

Ok, so here's my table structure:
+--------------------------+ +----------------+ +-------------------------------+
| pages | | menus | | menu_pages |
+--------------------------+ +----+-----------+ +-------------------------------+
| id | title | slug | | id | name | | menu_id | page_id | parent_id |
+-------+---------+--------+ +----+-----------+ +---------+---------+-----------+
| 1 | Home | index | | 1 | default | | 1 | 1 | 0 |
+-------+---------+--------+ +----+-----------+ +---------+---------+-----------+
| 2 | About | about | | 2 | footer | | 1 | 2 | 0 |
+-------+---------+--------+ +----+-----------+ +---------+---------+-----------+
| 3 | Test 1 | test-1 | | 1 | 3 | 2 |
+-------+---------+--------+ +---------+---------+-----------+
| 4 | Test 2 | test-2 | | 1 | 4 | 2 |
+-------+---------+--------+ +---------+---------+-----------+
| 5 | Test 3 | test-3 | | 1 | 5 | 4 |
+-------+---------+--------+ +---------+---------+-----------+
So basically, we have pages, menus, and a menu_pages linking table which specifies the menu, the page, and the parent of each menu item.
Here's my query:
$query = "SELECT pages.id, pages.title, pages.slug, menu_pages.parent_id
FROM menus, pages, menu_pages WHERE menus.name = '$menu'
AND menus.id = menu_pages.menu_id
AND pages.id = menu_pages.page_id";
$results = $db->Query($query);
Here's the question: How do I get the menu items properly nested under their respective parents in an array? I've tried quite a few things already, but none of them worked beyond simply 2 levels, so I won't clutter up the question with it. Obviously I need some kind of recursion in PHP, or to modify my query maybe in a way that I can get the SQL to return them properly?
It should look something like this in the output:
[0] => array(
'id' => 1,
'title' => 'Home',
'slug' => '/',
'parent_id' => '0'
)
[1] => array(
'id' => 2,
'title' => 'About',
'slug' => 'about',
'parent_id' => 0,
'sub_menu' => array(
[0] => array(
'id' => 3,
'title' => 'Test 1',
'slug' => 'test-1',
'parent_id' => 2
)
[1] => array(
'id' => 4,
'title' => 'Test 2',
'slug' => 'test-2',
'parent_id' => '2',
'sub_menu' => array(
[0] => array(
'id' => 5,
'title' => 'Test 3',
'slug' => 'test-3',
'parent_id' => 4
)
)
)
)
)
Thanks for the help!
This isn't quite as simple as it first sounds - if you want to get into how to do it with SQL, you are looking for a recursive sql statement.
Unfortunately mysql doesn't support this directly, and you would need to write a body of code to get it working. There is an example of how to do it here. Not simple.
http://explainextended.com/2009/03/17/hierarchical-queries-in-mysql/
In case you're interested in how to pick this apart, you would implement it in Oracle like this:
SELECT p.id, p.title, p.slug, mp.parent_id, level
FROM menu_pages mp
JOIN pages p ON ( p.id = mp.page_id )
JOIN menus m ON ( m.id = mp.menu_id )
CONNECT BY PRIOR mp.page_id = mp.parent_id
START WITH ( m.name = 'default' AND mp.parent_id = 0 )
You are basically saying:
START WITH a query for the top level of the menu
CONNECT that back to the result set by joining the parent to the child
You end up with a result set like this:
id title slug parent level
------------------------------------
1 Home index 0 1
2 About about 0 1
3 Test 1 test-1 2 2
4 Test 2 test-2 2 2
5 Test 3 test-3 4 3
All this actually gives you in addition to what you already have is:
The "level" of each point in the menu.
If a sub menu appeared multiple times in your structure it would be repeated correctly.
Sections of the menu that are not connected properly will not be returned.
So, for small, simple and consistent menus it's probably over-kill anyway.
Plus, even in this case you would need to process this in PHP to get the structure you're looking for.
So, using that as inspiration you can see how you could implement it in mysql by just doing the post processing.
You start off with your original query:
SELECT pages.id
, pages.title
, pages.slug
, menu_pages.parent_id
FROM menus
, pages
, menu_pages
WHERE menus.name = 'default'
AND menus.id = menu_pages.menu_id
AND pages.id = menu_pages.page_id
You can then loop over this result and build the array structure yourself manually.
In order to avoid the problem of recursion, we're instead going to take advantage of the fact that we can have two variables pointing at the same data structure - we're going to use references so that changing the value of the variable in one reference will change the value of the variable in the other.
I.E. The difficulty you get is finding the right point in the hierarchy to add each child. With references you don't have to.
Create an empty menu array
Loop over the results from your SQL statement
Create a copy of each menu item and put it into a simply indexed store (by the id of the item)
If you have the root menu item, add it to your menu array (as a reference)
If you don't have the root menu item, find the parent in your simple store and add your new item to it.
At the end you should have the nice nested structure you're looking for.
Like this:
<?php
// As if it came back from mysql...
// Assumed that it's ordered so that every possible parent appears before all its childern
$aResults = array( array( 'id' => 1, 'title' => 'Home', 'slug' => 'index', 'parent_id' => 0 )
, array( 'id' => 2, 'title' => 'About', 'slug' => 'about', 'parent_id' => 0 )
, array( 'id' => 3, 'title' => 'Test 1', 'slug' => 'test-1', 'parent_id' => 2 )
, array( 'id' => 4, 'title' => 'Test 2', 'slug' => 'test-2', 'parent_id' => 2 )
, array( 'id' => 5, 'title' => 'Test 3', 'slug' => 'test-3', 'parent_id' => 4 ) );
// the menu you're creating
$aMenu = array();
// the simple store of the menu items you're going to use to find the parents
$aBaseMenuIndex = array();
foreach( $aResults as $aMenuItem ) {
$aMenuItem['sub_menu'] = array();
// add your menu item to the simple store
$aBaseMenuIndex[ $aMenuItem['id'] ] = $aMenuItem;
if ( $aMenuItem['parent_id'] == 0 ) {
// if it's a base menu item, add it to the menu
$aMenu[] =& $aBaseMenuIndex[ $aMenuItem['id'] ];
} else {
// if it's not a base item, add it to the sub menu, using the simply indexed store to find it
// adding it here will also add it to $aMenu, as $aMenu contains a reference to this
$aBaseMenuIndex[ $aMenuItem['parent_id'] ]['sub_menu'][] =& $aBaseMenuIndex[ $aMenuItem['id'] ];
}
}
var_dump( $aMenu );

cake php list data and their related values to comma delemited id

My database have category table that is related to more than one city. In the categories table the city column has comma separated id for example 1, 2, 3.
When I retrieve data from categories table i want that the city column contain the corresponding city names instead of city id.
$categoryDetails = $this->Category->find('first',array('conditions'=>array('slug'=> $slug)));
Array
(
[Category] => Array
(
[id] => 10
[parent_id] => 2
[city] => 2, 3, 4, 5, 6, 7, 8, 9, 10
[slug] => college
[type] =>
[lft] => 31
[rght] => 32
[name] => College
[description] => College
[image_name] => 1376938860_1185824_431052847008731_328184125_n.jpg
[created] => 1376938860
[modified] => 1376938860
)
)
CakePHP is designed to handle model relationships, what you're doing is completely circumventing what Cake has been designed to do. Furthermore, in general you do not want to link entries in separate tables by storing ids in a comma separated list. http://book.cakephp.org/2.0/en/models/associations-linking-models-together.html
If a city will only ever belong to one category, use a hasMany relationship. If a city can belong to many categories, use a HABTM relationship.
I'm guessing what you probably want is a HABTM relationship. Drop the city field from the categories table, and make an additional categories_cities table that has the fields category_id and city_id. For the example you gave, it should look like this:
category_id | city_id
10 | 2
10 | 3
10 | 4
10 | 5
10 | 6
10 | 7
10 | 8
10 | 9
10 | 10
Then add to your Category model the following:
public $hasAndBelongsToMany = array(
'City' =>
array(
'className' => 'City',
'joinTable' => 'categories_cities',
'foreignKey' => 'city_id',
'associationForeignKey' => 'category_id',
'unique' => true,
)
);
Once you've set up the relationship, Cake will naturally fetch the cities you've related to the category when you do a find for that category, assuming the model's recursive property is set to 0 or higher. (Defaultly, it's set to 1.) Alternatively, you can use the containable behavior.

2 attribute in 2-dimensional array php

I want to create a 2 dimensional array, which the second array has 2 attributes. Is it possible in php? Becuase I know it's possible in Pascal
example
| Doc | Term |
| 0 | 0 => 'Term1' |
| | 1 => 5 |
----------------------------
| 1 | 0 => 'Term'2' |
| | 1 => 2 |
My question is, How to create this 2-dimensional array and how to access each value?
Thank you
This is simple array nesting:
$a = array(array('Term1', 5), array('Term2', 2));
$a[1][1] === 2;
This is an extremely basic question. Consider consulting a php book or tutorial.
Yes, you just make the value of the item in the array, another array, you can do this as deep as you like. e.g.,
Creating the array
$doc = array(
array(
'Term1',
5
),
array(
'Term 2',
2
)
)
Since no ID is set, the id's are automatically generated, starting at 0. You can set the ID if you want like this:
$doc = array(
0 => array(
3 => 'Term1',
9 => 5
),
1 => array(
3 => 'Term 2',
10 => 2
)
)
Retrieving data from the array
$term1 = $doc[0][0];
echo $term1; // outputs 'Term 1'

How to extract all COMBO values of dropdown with iMacros and PHP

I need to extract the pricing data from a form. The form contain several dropdown options. All combo of options must be extracted.
Example of the form dropdown:
size => 1, 2, 3, 4, 5
type => 1, 2, 3, 4
color => 1, 2, 3
units => 1, 2, 3, 4, 5, 6, 7
So this particular product has 420 possible configurations size * type * color * units
How do I write some some sort of loop which will get all possible combinations?
TAG POS=1 TYPE=SELECT FORM=ACTION:/food/getPrice.do ATTR=NAME:size CONTENT=#1
By the way trying to use imacros to select an option by index as shown in the example above does not work. I am forced to select by specifying the value (such as: %1)
I also tried SET !DATASOURCE and imported a CSV file but it didn't loop through as I need it to.
--Just to clarify -- I need this kind of output (doesn't have to be in this order, but MUST output all possible combinations):
size => 1 type => 1 color => 1 units => 1
size => 1 type => 2 color => 1 units => 1
size => 1 type => 2 color => 2 units => 1
size => 1 type => 2 color => 2 units => 2
size => 1 type => 2 color => 2 units => 2
size => 1 type => 3 color => 1 units => 1
. . .
--Side Note--
If you know of how I can run this imacro from a shared server (or EC2) please advise. Thanks for the help! :)
You're looking for the cartesian product, which is described here in PHP: PHP 2D Array output all combinations

Categories