Jump to content

Recommended Posts

Posted

Hi everybody!

I'm new to PW and just did the beginner-tutorial “Hello Worlds”, a beginning ProcessWire tutorial --> Link
After extending the template from the original tutorial with a page_reference-Field (Page-Field value type is configured as single page),
PW throws a fatal error when i try to output multiple pages:

$planets = $pages->find("template=planet, sort=-title");

foreach($planets as $planet) {
	echo $planet->title;
	echo $planet->planet_reference->title;  
}

Should return three Pages, but throws the following error:

Quote

Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 262144 bytes) in /Applications/MAMP/htdocs/extranet/wire/core/Page.php on line 1651
Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 262144 bytes) in Unknown on line 0

When i try to output the field with a single page, everything just works fine:

$planet = $pages->get(1018);

echo $planet->title;
echo $planet->planet_reference->title;

I've tried to solve the problem with myself (and google), but i can't fix the error.
Thanks a lot!

My enviroment:
OSX Mojave / MAMP (PHP 7.2), PW v 3.0.123

Posted (edited)

Hi @bernhard - and greetings from Tirol ?
Yes I've allready installed Tracy-Debugger and get the same error.
It can't be an endless loop, because, even if I enter the code directly into the tracy debugger console, the same error happens.
Two outputs work fine, after a third one a error occurs...

screenshot_1.png.7c58c48778494a6ccee068fbdbc27b6e.png
screenshot_2.png.77367c90b7ab4f42cc0c13629ce7c833.png

Thanks for your help!

Manuel

Edited by Manuel
Posted

Is planet_reference of page 1018 pointing to itself?

BTW: Use dump() or the shorthand d() better than echo in the console ? 

  • Like 1
Posted
7 minutes ago, bernhard said:

Is planet_reference of page 1018 pointing to itself?

 

If that's indeed the case: To avoid this, in your pageref field definition, use "selectable pages" > "selector string" and then insert this condition: id!=page.id to avoid references to itself.

  • Like 1
Posted

I think even if that was the case it should not end in such an error, but I don't have time to test it right now and maybe others will have better ideas ? 

Posted
15 hours ago, bernhard said:

Is planet_reference of page 1018 pointing to itself?

BTW: Use dump() or the shorthand d() better than echo in the console ? 

Thank you for the hints! Unfortunately the error occures on every page, also on the backend (TracyDebugger Console).

Posted

Here's a way to find all self-referencing page fields. Open your MySQL interface (MySQL Workbench, phpMyAdmin, adminer, whatever...) and execute the following query:

SET @oldgcmaxlen = @@group_concat_max_len;
SET SESSION group_concat_max_len = 32768;

SELECT GROUP_CONCAT(querystring SEPARATOR 'UNION\n') as sqlstring
FROM (
	SELECT 1 as something,
	CONCAT(
		'SELECT x.pages_id as id, y.name, z.data as title, \'',
        a.name,
        '\' as fieldname\n',
        'FROM field_',
		a.name,
		' x\n',
        'JOIN pages y ON y.id = x.pages_id JOIN field_title z ON z.pages_id = x.pages_id WHERE x.pages_id = x.data\n'
	) as querystring
	FROM fields a
	WHERE a.type = 'FieldtypePage'
) as inmemtbl
GROUP BY something
;

SET SESSION group_concat_max_len = @oldgcmaxlen;

The result will be a UNION query that checks all your page fields for direct recursions. Here's an example:

SELECT x.pages_id as id, y.name, z.data as title, 'permissions' as fieldname
FROM field_permissions x
JOIN pages y ON y.id = x.pages_id JOIN field_title z ON z.pages_id = x.pages_id WHERE x.pages_id = x.data
UNION
SELECT x.pages_id as id, y.name, z.data as title, 'roles' as fieldname
FROM field_roles x
JOIN pages y ON y.id = x.pages_id JOIN field_title z ON z.pages_id = x.pages_id WHERE x.pages_id = x.data
UNION
SELECT x.pages_id as id, y.name, z.data as title, 'language' as fieldname
FROM field_language x
JOIN pages y ON y.id = x.pages_id JOIN field_title z ON z.pages_id = x.pages_id WHERE x.pages_id = x.data
UNION
SELECT x.pages_id as id, y.name, z.data as title, 'pagesel' as fieldname
FROM field_pagesel x
JOIN pages y ON y.id = x.pages_id JOIN field_title z ON z.pages_id = x.pages_id WHERE x.pages_id = x.data

Copy that query into the SQL editor and execute it. If there are any recursions, you will see them listed with the page id, page name, page title and field name.

recursionexample.png.2f5bf2d48d661c51942543e065e3152a.png

  • Like 6
Posted
1 hour ago, Manuel said:

Thank you for the hints! Unfortunately the error occures on every page, also on the backend (TracyDebugger Console).

This statement seems like you didn't get what I tried to say.

17 hours ago, dragan said:

Is planet_reference of page 1018 pointing to itself?

Means that you have maybe selected page 1018 in the page-reference-field "planet_reference" of page 1018. That means the planet_reference of 1018 points to page 1018 (itself) and could maybe end in an endless loop?

No idea if that is possible and it would throw such an error. I think PW should be clever enough to prevent such errors. If not, that would be worth an issue report!

  • Like 1
Posted
5 minutes ago, Manuel said:

PW even doesn't offer a self-refference in the selectbox.

OK great for PW, bad for solving your problem ? Then I'm out of ideas, sorry ? 

Posted

No problem and thanks for your advise! I'll try to solve the issue and will report the solution in this thread - hopefully ?

Posted
17 minutes ago, Robin S said:

And page 1017 references page 1018, right? It's a circular reference issue that seems to happen when two pages that reference each other are both loaded into memory. Probably connected to this issue: https://github.com/processwire/processwire-issues/issues/572

 

Hi @Robin S,

that would make sense. But after checking the references (only 4 pages), I can tell you they don't reference each other. Here's another screenshot.
The references are as follows:

earth (1016) --> mars (1017)
mars(1017) --> jupiter (1018)
jupiter(1018) --> merkur (1045)
merkur(1045) --> earth(1016)
screenshot.png.e0aa515e08cec5faf06647e921e839b1.png

After removing one of the d() functions as shown above, the fatal error doesn't occure.
The problem is, I want to get all pages with there references, not only n-1 ?

Posted
29 minutes ago, Manuel said:

But after checking the references (only 4 pages), I can tell you they don't reference each other.

But they do. Not as directly as I first suggested, but there is a kind of circularity within the pages you are loading...

2019-04-18_002135.png.8dd43c264f6be780b30842eae4c45344.png

As soon as your loaded pages form a circularity the out of memory occurs. This kind of problem seems to happen particularly when a "single page" value type is defined in the field settings. I expect that if you change the field setting to "multiple pages" then the error won't occur.

2019-04-18_003019.png.f8f3ce7652f120af609bf01721f528ef.png

To be clear, I think that it ought to be possible to load pages like this using a single page field without any error occurring. I encourage you to make a report in the PW issues repo: https://github.com/processwire/processwire-issues/issues  add a comment to the existing issue: https://github.com/processwire/processwire-issues/issues/572

  • Like 2
Posted
2 minutes ago, Robin S said:

I think that it ought to be possible to load pages like this using a singe page field without any error occurring

Wouldn't that be fixed too with the correction in the linked issue? The cited error (Wire.php line 1069) points to setTrackChanges.

  • Like 1
Posted
2 minutes ago, BitPoet said:

Wouldn't that be fixed too with the correction in the linked issue? The cited error (Wire.php line 1069) points to setTrackChanges.

Ah, yes, you're right. So no need for a new issue, but maybe @Manuel might like to add a link to this topic in the issue discussion to hopefully bring the issue back to Ryan's attention. ?

Posted

@Manuel, could you try commenting out the setTrackChanges method in core/Wire.php and replacing it with the following code?

	protected static $resetTrackChangesItems = array();

	public function resetTrackChanges($trackChanges = true) {
		$isRoot = count(self::$resetTrackChangesItems) == 0;
		
		self::$resetTrackChangesItems[$this->id] = true;
		
		parent::resetTrackChanges($trackChanges);
		foreach($this->data as $key => $value) {
			if(is_object($value) && $value instanceof Wire && $value !== $this) {
				if($value instanceof Page && isset(self::$resetTrackChangesItems[$value->id])) continue;
				$value->resetTrackChanges($trackChanges);
			}
		}
		
		if($isRoot) self::$resetTrackChangesItems = array();
		
		return $this; 
	}

 

  • Like 1
Posted
1 hour ago, Robin S said:

2019-04-18_003019.png.f8f3ce7652f120af609bf01721f528ef.png

Switching the field to Multiple Pages works fine, but for now the user is able to assign multiple planets instead of just one ?

Posted
7 hours ago, Manuel said:

Switching the field to Multiple Pages works fine, but for now the user is able to assign multiple planets instead of just one

The single/multiple value type determines the type of value returned by the field. The number of pages the user can assign in Page Edit is determined by the input field type. So it's possible to use a single page selection input type (e.g. select) with a multiple page value type. But regardless we all agree that the issue should be fixed for the single page value type.

Posted
11 hours ago, Robin S said:

The single/multiple value type determines the type of value returned by the field. The number of pages the user can assign in Page Edit is determined by the input field type. So it's possible to use a single page selection input type (e.g. select) with a multiple page value type. But regardless we all agree that the issue should be fixed for the single page value type.

You're right, a select-input would be a neat workaround to prevent a user to assign multiple pages. I agree, issue should be fixed. As a newbie tat behaviour was a bit confusing to me. Thanks to everybodies help: @Robin S @adrian @BitPoet @bernhard ?

  • Like 1
Posted

My final solution to output all fields as a JSON-Object:

 

<?php

$planets = $pages->find("template=planet, sort=-title");
$planets_array = array();

foreach($planets as $planet) {
    
	$moon_array = array();
	$moons = $planet->planet_moons;
	
	foreach($moons as $moon)
	{
		$moon_array[] = $moon->title;
	}
	
    $planets_array[] = array(
        'title' => $planet->title,
		'created' => date("H:i:s d.m.Y", $planet->created),
		'modified' => date("H:i:s d.m.Y", $planet->modified),
		'type' => $planet->planet_type,
        'age' => $planet->planet_age,
		'color' => ucfirst($planet->planet_color->title),
		'moons' => $moon_array,
		'summary' => $planet->planet_summary,
		'foto' => $_SERVER['SERVER_NAME'] . $planet->planet_foto->url,
		'planet-reference' => $planet->planet_reference[0]->title
    );
}

$planets_json = json_encode($planets_array, true);
echo $planets_json;

?>

Output (JSON):

[{
	"title": "Merkur",
	"created": "20:25:29 16.04.2019",
	"modified": "14:06:19 17.04.2019",
	"type": "W\u00fcstenplanet",
	"age": "800.812",
	"color": "Brown",
	"moons": ["Merkur Mond 1", "Merkur Mond 2"],
	"summary": "Beschreibung gibt es noch erst eine sehr kurze. hier gibt es noch nicht viel zu lesen...",
	"foto": "extranet\/site\/assets\/files\/1045\/merkur.jpg",
	"planet-reference": "Earth"
}, {
	"title": "Mars",
	"created": "17:54:58 07.04.2019",
	"modified": "14:06:08 17.04.2019",
	"type": "Terrestrial moon",
	"age": "4.500.000.712",
	"color": "Red",
	"moons": ["Phobos", "Deimos"],
	"summary": "Mars is the fourth round planet from the Sun...",
	"foto": "extranet\/site\/assets\/files\/1018\/mars.jpg",
	"planet-reference": "Merkur"
}, {
	"title": "Jupiter",
	"created": "17:28:14 07.04.2019",
	"modified": "14:05:52 17.04.2019",
	"type": "Great Gas Giant",
	"age": "4,5 Billion",
	"color": "Yellow",
	"moons": ["Io", "Europa", "Kallisto", "Ganymed", "Amalthea", "Himalia", "Elara"],
	"summary": "Jupiter is the fifth planet...",
	"foto": "extranet\/site\/assets\/files\/1017\/jupiter.jpg",
	"planet-reference": "Mars"
}, {
	"title": "Earth",
	"created": "17:13:23 07.04.2019",
	"modified": "14:05:40 17.04.2019",
	"type": "Terrestrial Planet",
	"age": "15.56 Billion",
	"color": "Purple",
	"moons": ["Moon"],
	"summary": "Earth (or the Earth) is the third planet from the Sun...",
	"foto": "extranet\/site\/assets\/files\/1016\/earth-1.jpg",
	"planet-reference": "Jupiter"
}]

 

  • Like 1
Posted

Nice! ?

On mobile, but you can even make it simpler by using 

1 hour ago, Manuel said:

'moons' => $moon_array,

'moons' => $planet->planet_moons->each('title')

See the API docs for WireArray. It has some nice features ?

Posted

Thank you @bernhard

7 minutes ago, bernhard said:

'moons' => $planet->planet_moons->each('title')

I knew there would be a faster way to get the job done. PW is geeting better and better to me ?

  • Like 1

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
×
×
  • Create New...