Jump to content

Need clarification from PHP side.


Zeka
 Share

Recommended Posts

Guys, I need some clarifications here.
I'm building catalog menu and depending on whether a page has children with 'category' template I change some part of my selector.

Code that I use:

<?php namespace ProcessWire;

$layout->setTemplate('sidebar');

$selector = [
	'template'   => 'product',
	'sort'       => 'title',
	'categories' => page('id'),
	'limit'      => 9
];

if (page()->children->has('template=category')) {
	$selector['categories'] = page()->children('template=category')->add(page());
}

$products = pages($selector);
$sub_categories = page()->children('template=category');

bd(page()->children()); // 7
bd(page()->children('template=category')); // 8 

As you can see in the first 'bd' I get 7 children and that is the right result. But it the second I get 8 children ( 7 children and current page which was added in if statement).

I can't understand it from PHP side. For me, it's unintended behaviour as I'm calling function and waiting for a new result, but instead, I'm getting the result from an object from the previous call.

 

Link to comment
Share on other sites

d($page->children()->count); // 7

$foo = $pages->get(1);
$page->children()->add($foo);
d($page->children()->count); // 8

d($page->children('id>2000')->count); // 3
$page->children('id>2000')->add($foo);
d($page->children('id>2000')->count); // 4

$pages->uncacheAll();
d($page->children('id>2000')->count); // 3

 

  • Like 2
Link to comment
Share on other sites

@bernhard's post gives you the clue - it's to do with PW's built-in caching.

$page->children() is a method that queries the database. You want to minimise the number of requests to the database because going to the DB is a lot slower than working with objects in memory. In your code you call $page->children() five times, so the expectation is that this would mean five trips to the DB... except that PW tries to help you out and caches the results to avoid unnecessary DB queries.

But the exact workings of this caching are undocumented (as far as I know) and so I'd say it's best practice not to rely on it. It would be better to consciously minimise the DB requests in your code - it would make things clearer (i.e. avoid the confusion you're getting from the behind-the-scenes caching) and it's a good habit to get into for when you're working with other PHP projects that might not cache DB query results like PW does.

You could rewrite your code like this:

$layout->setTemplate('sidebar');

$selector = [
	'template'   => 'product',
	'sort'       => 'title',
	'categories' => page('id'),
	'limit'      => 9
];

// Just get the children from the DB once
// I assume you need all the children at some point later in the code because you dump page()->children() in your example.
// If you don't need all the children then just get the categories directly with page()->children('template=category')
$children = page()->children();

// Get the categories from the children PageArray (happens in memory)
$categories = $children->find('template=category');

// If there are any categories then modify $selector
if($categories->count) {
	$categories->add(page());
	$selector['categories'] = $categories;
}

bd($children);
bd($categories);

And this might be getting into the zone of micro-optimisation but you could consider if you actually need full Page objects in a PageArray or if you only need the IDs (reduces the memory footprint):

$category_ids = page()->children('template=category', ['findIDs' => 1]);;
if(count($category_ids)) {
	$category_ids[] = page()->id;
	$selector['categories'] = $category_ids;
}

 

  • Like 6
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...