cakePHP 2.0 find('threaded') Issue - php

I am running the following in my Jobs controller.
$this->set('jobs', $this->Job->find('threaded', array('conditions' => array('Job.id' => 20))));
Now in my view I am displaying $jobs in my foreach loop fine, but my issue is I have children linked to Job.id using the field parent_id. I know the link works fine because I can see the children in the array.
Array
(
[0] => Array
(
[Job] => Array
(
[id] => 20
[parent_id] => 0
[rght] => 2
[lft] => 1
[client_id] => tasd
[contact] => asdf
[email] => sdf
[address] =>
[lat] =>
[long] =>
[user_id] => 1
[request_type_id] => Electrical
[date_start] => 0000-00-00 00:00:00
[date_end] => 0000-00-00 00:00:00
[date_complete] => 0000-00-00 00:00:00
[date_closed] => 0000-00-00 00:00:00
[status] => completed
[brief_desc] => aasdf
[desc] => asdfasdf
[cost_est] => 3434.00
[cost_actual] =>
[created] => 2011-12-18 20:39:24
[modified] => 2011-12-18 20:39:24
)
[Children] => Array
(
[0] => Array
(
[id] => 21
[parent_id] => 20
I would like to display the child jobs under the parent jobs. Exactly how nested comments should work. Any help would be great.

Look at the SQL that find('threaded') is generating. You are asking for all Jobs with an id of 20 (Rather than all Jobs that are children of Job 20)
Since you have a lft and rght field, I assume you have the Tree behaviour attached. This means you can use children().
$this->Job->id = 20;
$this->Job->children();
However, this will give you a flat array, rather than a nested array. If you need a nested array then use the lft and rght columns in the find('threaded') call.
$parentJob = $this->Job->find('first', array(
'conditions' => array(
'Job.id' => 20
)
);
$children = $this->Job->find('first', array(
'conditions' => array(
'Job.lft BETWEEN ? AND ?' => array($parentJob['Job']['lft'], $parentJob['Job'])['rght']
)
);
Of course you could get that down to a single query, but I'll leave that 'as an exercise for the reader' (I should have been a Textbook writer)

If anyone want to display the find('threaded') result in view of cakephp, they can use this:
Controller code:
$params = array('recursive' => -1,'fields' => 'Category.id, Category.name, Category.parent_id');
$categories = $this->Category->find('threaded',$params);
And show your threaded result in view like this:
foreach($categories as $category):
$category_name = $category['Category']['name'];
foreach($category['children'] as $children):
$sub_category = $children['Category']['name'];
endforeach;
endforeach;
I don't know its the proper way to display the result or not, but it's working fine.
Hope its help for someone :)
I'm new to cakephp and learning basics. If found any mistake, please forgive me.

Please Read below link
http://bakery.cakephp.org/articles/MrRio/2006/09/24/threaded-lists

I realize this is old, but I was trying to figure this out today and was able to make it work (somewhat oddly) with the following:
$this->set('jobs',
$this->Job->find('threaded', array(
'conditions' => array(
'OR' => array(
Job.id' => 20,
Job.parent_id => 20
)
)
)
);
Hope this saves someone some time...

Related

PHP build associated array from previous array

I'm trying to make a parent child like array out of a previous array of things, some are duplicates, some are not.
I have an array that spits out like so:
[0] => Array
(
[parent] => dogs
[child_cat_1] => category one
[child_cat_2] => category two
[title] => Title
[price] => 9.49
[sku] => 3558505550
[old_post_id] => 110
)
[1] => Array
(
[parent] => cats
[child_cat_1] => category one
[child_cat_2] => category six
[title] => Title
[price] => 16.49
[sku] => 2251752419
[old_post_id] => 113
)
[2] => Array
(
[parent] => cats
[child_cat_1] => category three
[child_cat_2] => category nine
[title] => Title
[price] => 59.99
[sku] => 7944100467
[old_post_id] => 114
)
[3] => Array
(
[parent] => dogs
[child_cat_1] => category one
[child_cat_2] => category two
[title] => Title
[price] => 69.99
[sku] => 85932810243
[old_post_id] => 117
)
I'm having a real hard time creating a new array based off these arrays, and turning it into an array of parents and children.
I tried doing what this post said, but I couldn't get it to work as I'm not entirely sure of what the 'parent' is going to be.
I tried doing this, but I can't figure out how to factor in child_cat_2, and also remove the duplicates. I've also read pretty much every "Building Hierarchy out of array" on Stackoverflow, but I just can't figure this one out.
foreach($new_array as $k => $v){
$array[$v['parent']] = $v['child_cat_1'];
}
Ideally, what I'm trying to accomplish is arranging each child_cat_2 under child_cat_1, and then both under parent, but then also remove the duplicates. I think the parent only has 11 types, but the two children have up to 100 each.
Can someone point me in the right direction to get these arrays sorted out.
What you've described is a 3-level nested array. The code you've posted certainly won't accomplish that. You have nodes with four properties other than your array structure, so that is what you should build in a loop. Then you place them into your structure depending on the other three properties.
$results = array();
foreach ($data as $datum){
$node = array(
'title' => $datum['title']
'price' => $datum['price']
'sku' => $datum['sku']
'old_post_id' => $datum['old_post_id']
);
if (!is_array($results[$datum['parent']])) {
$results[$datum['parent']] = array();
}
if (!is_array($results[$datum['parent']][$datum['child_cat_1']])) {
$results[$datum['parent']]
[$datum['child_cat_1']] = array();
}
if (!is_array($results[$datum['parent']][$datum['child_cat_1']][$datum['child_cat_2']])) {
$results[$datum['parent']]
[$datum['child_cat_1']]
[$datum['child_cat_2']] = array();
}
$results[$datum['parent']]
[$datum['child_cat_1']]
[$datum['child_cat_2']][] = $node;
}

looping through an object twice - php

I'm playing around with a zencart trying to make it do what I want but I've run out of ideas of what to Google.
When I query the DB using the zencart function the software returns an object which looks like:
queryFactoryResult Object
(
[is_cached] =>
[resource] => Resource id #117
[cursor] => 11
[EOF] =>
[fields] => Array
(
[products_id] => 5582
[products_description] => description here
[products_name] => Lucky magnet – Each petal...
[products_type] => 1
[products_quantity] => 0
[products_image] => EachPetalMag.jpg
[products_price] => 3.4000
[products_status] => 1
[products_ordered] => 14
[master_categories_id] => 21
[supplier_id] => 7
)
)
I have to loop through once to count how many master_categories are there before I can do anything else:
while (!$products->EOF) {
$products_count++;
$supcats[$products->fields['master_categories_id']] = $products->fields['master_categories_id'];
$products->MoveNext();
}
I then need to loop through the object again using the while loop like above, I've tried:
reset($products);
and
$products->EOF = FALSE;
but they don't work. Is there a way to do this with out having to send the query again?
Regular array-like operations on Zen Cart queryFactoryResult won't work as it's not an array, so this won't work:
reset($products);
To loop through the variable again use queryFactoryResult->Move(row_number) method:
$products->Move(0);

Cakephp using Set class to fetch data with key starting at zero

I'm using Set class of Cakephp to format the find returned array but cannot seem to find a way to get the counter starting at zero and auto-increment for array keys so it is like
[0] => 3
[1] => 6
[2] => 12
I'm currently using below query to get the data from my HasAndBelongsToMany table.
$interest_ids = Set::combine($this->User->Interestsub->find('threaded', array
(
'conditions' => array
(
'Interestsub.name' => $interests
),
//'fields' => array('Interestsub.id'),
'recursive' => -1
)
),
'{n}.Interestsub.id',
'{n}.Interestsub.id'
);
The reason why I need this is that I'm currently trying to get the returned array as part of bigger parent array preparing to be saved for SaveAll function. To be formatted properly, I need below nested array coming out:
[0] => Array
(
[interestssub_id] => 12
[user_id] => 2
)
[1] => Array
(
[interestssub_id] => 22
[user_id] => 2
)
[2] => Array
(
[interestssub_id] => 32
[user_id] => 2
)
Is there a way we can use Combine class to format the returned array like above?
There's no real reason to use the Set class in this case. Just use good old fashioned php:
$threaded = $this->User->Interestsub->find('threaded', array(
'conditions' => array(
'Interestsub.name' => $interests
),
'recursive' => -1
));
$interest_ids = array();
foreach ($threaded as $thread) {
$interest_ids[] = array(
'interestssub_id' => $thread['Interestsub.id'],
'interestssub_id' => $thread['Interestsub.user_id']
);
}

How to associate models correctly cakephp

I have a scenario where i have templates which has many themes.
Clear enough that my relation will be template hasmany themes
I wanna show the template with number of themes and i am applying this code:
$this->Template->recursive = 2;
$this->Template->bindModel(
array(
'hasMany' =>array(
'TemplateTheme'=>array(
'className'=>'TemplateTheme',
'fields' => 'count(TemplateTheme.id) AS themes'
)
)
),false
);
$this->paginate = array(
'order' => array('Template.modified DESC'),
'limit' =>$limit
);
$template = $this->paginate('Template');
pr($template);die();
but i am getting is
Array
(
[0] => Array
(
[Template] => Array
(
[id] => 1
[name] => churchDesign
[status] => Active
[created] => 2011-10-24 10:37:23
[modified] => 2011-10-25 15:16:46
)
[TemplateTheme] => Array
(
[0] => Array
(
[template_id] => 1
[TemplateTheme] => Array
(
[0] => Array
(
[themes] => 3
)
)
)
)
)
[1] => Array
(
[Template] => Array
(
[id] => 2
[name] => blossoms
[status] => Active
[created] => 2011-10-19 00:00:00
[modified] => 2011-10-24 14:05:27
)
[TemplateTheme] => Array
(
)
)
)
The problem here is it is counting all the themes in first array(1st template).see [TemplateTheme] => Array
(
[0] => Array
(
[themes] => 3
)
the third theme actually belongs to the 2nd template.The relation is
template_id is in themes table to represent each theme for a template.
Template 1 has 2 themes and template 2nd has one theme and currently its showing all the three themes in the first template.
i want it like this way
templatename1
count of themes 1st template
template name 2
count of themes of 2nd template
Please tell me the right way to do this.
If you wanted to get the count of the Themes per each Template, the most elegant way is to use counterCache.
Another way is to use Containable behavior, which fetches only the related data which you wish, and then count the fetched data array in PHP.
After you attach the containable behavior to the Template model, some code like this should work:
$allTemplates = $this->Templates->find('all', array(
'contain' => 'TemplateTheme.name'
));
foreach($allTemplates as $template){
$currentThemeCount = count($template['TemplateTheme']);
foreach($template['TemplateTheme'] as $theme){
echo $theme['name'];
}
}
Hope this helps someone along the way.
you can count the themes array like
foreach($template as $t){
count($t['TemplateTheme'])
}
hope this helps
You should be using the find('count') method instead of using a virtual 'count' field like you're doing now. For example:
$allTemplates = $this->Template->find('all');
foreach($allTemplates as $data) {
$templateCount = $this->Template->TemplateTheme->find('count', array(
'conditions' => array(
'TemplateTheme.template_id' => $data['Template']['id']
)
));
// $templateCount should now contain the count of this specific template. Foreach will continue recursion for all others.
}

cakephp - sorting by a second level association in paginate

I am playing around with a quotes database relating to a ski trip I run. I am trying to list the quotes, but sort by the person who said the quote, and am struggling to get the paginate helper to let me do this.
I have four relevant tables.
quotes, trips, people and attendances. Attendances is essentially a join table for people and trips.
Relationships are as follows;
Attendance belongsTo Person hasMany Attendance
Attendance belongsTo Trip hasMany Attendance
Attendance hasMany Quote belongs to Attendance
In the QuotesController I use containable to retrieve the fields from Quote, along with the associated Attendance, and the fields from the Trip and Person associated with that Attendance.
function index() {
$this->Quote->recursive = 0;
$this->paginate['Quote'] = array(
'contain' => array('Attendance.Person', 'Attendance.Trip'));
$this->set('quotes', $this->paginate());
}
This seems to work fine, and in the view, I can echo out
foreach ($quotes as $quote) {
echo $quote['Attendance']['Person']['first_name'];
}
without any problem.
What I cannot get to work is accessing/using the same variable as a sort field in paginate
echo $this->Paginator->sort('Name', 'Attendance.Person.first_name');
or
echo $this->Paginator->sort('Location', 'Attendance.Trip.location');
Does not work. It appears to sort by something, but I'm not sure what.
The $quotes array I am passing looks like this;
Array
(
[0] => Array
(
[Quote] => Array
(
[id] => 1
[attendance_id] => 15
[quote_text] => Hello
)
[Attendance] => Array
(
[id] => 15
[person_id] => 2
[trip_id] => 7
[Person] => Array
(
[id] => 2
[first_name] => John
[last_name] => Smith
)
[Trip] => Array
(
[id] => 7
[location] => La Plagne
[year] => 2000
[modified] =>
)
)
)
I would be immensely grateful if someone could suggest how I might be able to sort by the the first_name of the Person associated with the Quote. I suspect my syntax is wrong, but I have not been able to find the answer. Is it not possible to sort by a second level association in this way?
I am pretty much brand new with cakephp so please be gentle.
Thanks very much in advance.
I've had the similar problem awhile back. Not with sort though. Try putting the associated table in another array.
echo $this->Paginator->sort('Name', 'Attendance.Person.first_name');
change to:
echo $this->Paginator->sort('Name', array('Attendance' => 'Person.first_name'));
Hope this helps
i'm also looking for help with this.
so far i've found that you can sort multi level associations in controller's pagination options after using the linkable plugin https://github.com/Terr/linkable.
but it breaks down when you try to sort form the paginator in the view. i'm using a controller for magazine clippings. each clipping belongs to an issue and each issue belongs to a publication.
$this->paginate = array(
"recursive"=>0,
"link"=>array("Issue"=>array("Publication")),
"order"=>array("Publication.name"=>"ASC",
"limit"=>10);
after debugging $this->Paginator->params->paging->Clipping in the view, you can see that the sort is described in two separate places, "defaults" and "options". the sort info needs to be present in both for it to work in the view.
here is after setting order in controller:
[Clipping] => Array
(
[page] => 1
[current] => 10
[count] => 6685
[prevPage] =>
[nextPage] => 1
[pageCount] => 669
[defaults] => Array
(
[limit] => 10
[step] => 1
[recursive] => 0
[link] => Array
(
[Issue] => Array
(
[0] => Publication
)
)
[order] => Array
(
[Publication.name] => ASC
)
[conditions] => Array
(
)
)
[options] => Array
(
[page] => 1
[limit] => 10
[recursive] => 0
[link] => Array
(
[Issue] => Array
(
[0] => Publication
)
)
[order] => Array
(
[Publication.name] => ASC
)
[conditions] => Array
(
)
)
)
and here is after using $this->Paginator->sort("Publication","Publication.name");.
notice the options array is empty.
[Clipping] => Array
(
[page] => 1
[current] => 10
[count] => 6685
[prevPage] =>
[nextPage] => 1
[pageCount] => 669
[defaults] => Array
(
[limit] => 10
[step] => 1
[recursive] => 0
[link] => Array
(
[Issue] => Array
(
[0] => Publication
)
)
[order] => Array
(
[Publication.name] => DESC
)
[conditions] => Array
(
)
)
[options] => Array
(
[page] => 1
[limit] => 10
[recursive] => 0
[link] => Array
(
[Issue] => Array
(
[0] => Publication
)
)
[order] => Array
(
)
[conditions] => Array
(
)
)
does one really need to modify the paginator class to make this work?
UPDATE:
i found out the problem:
in the core cake controller paginator merges default and options to create the find query.
but the options array is empty when using linkable to sort. because options is listed after default it overrides default and the empty array replaces the default array of options.
solution to this is extending the paginate function inside of app_controller.php and unsetting the options array order value if it is empty:
(line 1172 in cake/libs/controller/controller.php)
if(empty($options["order"])){
unset($options["order"]);
}
then the options will not be overwritten by thte blank array.
of course this should not be changed inside of controller.php, but put it in app_controller.php and move it to your app folder.
On CakePHP 3 this problem can be solved by adding 'sortWhitelist' params to $this->paginate on your controller.
$this->paginate = [
// ...
'sortWhitelist' => ['id', 'status', 'Attendance.Person.first_name']
];
And then in your view:
echo $this->Paginator->sort('Name', 'Attendance.Person.first_name');
This is noted in the docs:
This option is required when you want to sort on any associated data, or computed fields that may be part of your pagination query:
However that could be easily missed by tired eyes, so hope this helps someone out there!

Categories