Jump to content

Outputting relational data nested in a repeater field


kathep
 Share

Recommended Posts

I am having trouble working out the syntax for outputting relational data that is nested inside a repeater field. I only started using repeater fields a couple of days ago, and pagearray fields three weeks ago.
 
The problem involves the following templates and fields:

  • class
    • lesson_plan_section (repeater field, containing the following)
      • lesson_plan_time
      • lesson_plan_subject
      • lesson_plan_section_type (pagearray field)
      • online_tools (pagearray field)
  • lesson_plan_section_type
    • title
    • lesson_plan_section_description
  • online_tools
    • title
    • url

I have outputted the regular text areas of the repeater field fine, like this:

*table beginning code snipped off*

foreach($section as $item) {
     $lesson_list .= "<tr><td>" . $item->lesson_plan_time . "</td><td><p><strong>" . $item->lesson_plan_subject . "</strong><br> </td><td> </td></tr>"; 
}

*table end code snipped off*

I can get the repeater fields to output, and usually I can get pagearray fields to output, but I am having trouble now that the pagearray is inside a repeater field. 

Do I need to add the repeater field to my syntax? I mean like this:

online_tools=$page->lesson_plan_section->online_tools

I have been doing various, ridiculous things with my code to try to replace the '$nbsp;'s with the lesson_plan_section_description and online_tools pages selected in the repeater field, but without luck.

 
I know I that before output, I have to find the pages like so:

$section_type = $page->lesson_plan_section_type; 

$tools = $page->online_tools;

$section_find = $pages->find("template=lesson_plan_section_type, lesson_plan_section_type=$page->lesson_plan_section_type");

$ot_find = $pages->find("template=online_tools, online_tools=$page->online_tools");

But this is as far as I got. 

Can someone provide me with a hint to get me a little further?

Link to comment
Share on other sites

Read this very quickly....

Since a repeater returns a PageArray, you've done well to foreach it. However, lesson_plan_section_type and online_tools are also PageArrays, so inside your first foreach, you also need to foreach them (traverse the array) (i.e. a nested foreach $item as $abc inside your first foreach - but you would have to first check if $item is an array, otherwise PHP will throw an error since the text fields will not be arrays [i.e. cannot be foreach'ed]). Things can get a bit confusing though with nested foreachs. There are other techiniques like using a counter (...sorry I am in a rush and can't explain now...)...

I am curios why 'lesson_plan_section_type' is a PageArray. Are you actually selecting multiple pages in that page field or a single page field would do? That would save you looping through the pagefield. 

Sorry if I have confused you further...Hopefully you'll get better answers soon :-).

  • Like 1
Link to comment
Share on other sites

@kongondo Yes, you're right, lesson_plan_section_type doesn't need to be a pagearray - it would be better as a page. So that simplifies one part of the problem!

I agree, my experience so far has been that nested foreachs get confusing! But your answer has helped me the next step of the way. I will try changing the lesson_plan_section_type to a page instead of a pagearray, adding an if statement to my dodgy code, and see what happens.

Stay tuned...

UPDATE

So now I have two, related problems...

1. How to output lesson_plan_section_type as a page for each repeater, and

2. How to output online_tools as a pagearray for each repeater.

I have been trying to figure this out for ages, testing using $fields, adding nested foreach statements (though I have little idea what is correct for these). The closest I came to success was using a $page->get() function to call the lesson_plan_section_type page. This at least showed an output, but all it did was take the first lesson_plan_section_type page from the list and add it every repeater instance. Not what I was trying to do!

Please let me know a clue if you have some more knowledge than me on this.

Link to comment
Share on other sites

i only read the last post.. but if you have repeaters and want to output them as pages... i think you may need to use segments, and then in the repeater have a required field for the page name;

then in the parent page check for the URL segment1, and compare it to the available repeaters; if it is a match then output the data from the repeater; if not output a 404.

you may want to break out your code into some include files, or use functions if you are getting lost in nested stuff;

online_tools sounds like a simple case of using the new api for imploding;

https://processwire.com/talk/topic/5098-new-wirearray-api-additions-on-dev/?p=49166

Link to comment
Share on other sites

UPDATE

So now I have two, related problems...

1. How to output lesson_plan_section_type as a page for each repeater, and

2. How to output online_tools as a pagearray for each repeater.

I have been trying to figure this out for ages, testing using $fields, adding nested foreach statements (though I have little idea what is correct for these). The closest I came to success was using a $page->get() function to call the lesson_plan_section_type page. This at least showed an output, but all it did was take the first lesson_plan_section_type page from the list and add it every repeater instance. Not what I was trying to do!

Please let me know a clue if you have some more knowledge than me on this.

Untested + markup could be wrong: Here's some heavily commented code. You might want to use shorter field names :D

Here's some homework if you haven't seen it yet :-)http://processwire.com/api/fieldtypes/repeaters/

//$section is the name of the repeater, in other words..
//$section is the REPEATERS and..
//$item is a SINGLE REPEATER within this group of repeaters
$lesson_list = '';
foreach($section as $item) {
	$lesson_list .= "
			<tr>
				<td>" . $item->lesson_plan_time . "</td>
				<td><strong>" . $item->lesson_plan_subject . "</strong></td>
				<td>" . $item->lesson_plan_section_type->title . "</td>
				<td>" . $item->lesson_plan_section_type->lesson_plan_section_description . "</td>
			        <td>";
			foreach($item->online_tools as $tool) {
			
				$lesson_list .=" <a href='" . $tool->url . "'>" . $tool->title . "</a>";

			}//end foreach $item->online_tools as $tool

	$lesson_list .= "</td></tr>";//close the table row and loop through the next $item until done 

}//end foreach $section as $item

/*
	$item->lesson_plan_time: a text field (lesson_plan_time)
	$item->lesson_plan_subject: a text field (lesson_plan_subject)
	
	$item->lesson_plan_section_type: lesson_plan_section_type
		# This is a Single PageField type, i.e. either:
		# 'Single page (Page) or boolean false when none selected' OR 
		# 'Single page (Page) or empty page (NullPage) when none selected'
		# It returns a Page Object (an instance of a Page) so we can directly reference its properties like:
		# $item->lesson_plan_section_type->title, OR 
                # $item->lesson_plan_section_type->whatever (e.g. child, name, other_non_array_field), etc.
			- $item is the repeater we are currently looping through
			- lesson_plan_section_type is a page object
			- title is a property of the page object in lesson_plan_section_type
                        - lesson_plan_section_description is a text field in the page object in lesson_plan_section_type

	$item->online_tools: online_tools
		# This is a Multiple PageField type, i.e.:
		# Multiple pages (PageArray)
		# We need to loop through it
		
*/
Edited by kongondo
  • Like 2
Link to comment
Share on other sites

@Macura and @Kongondo thank you for feedback!

I am very happy to have an untested code suggestion to play around with  :)

Now I see your code, it makes a lot of sense. I never would have thought of closing the table row in separate concat on my own, but now I see it, it seem so obvious!

This php/pw journey feels like traveling in another country and only knowing half the words. But I am learning fast.

I have seen the repeaters documentation, but one thing that is a stumbling block for me is that a lot of the output examples given in the docs use echo. But the templates use a better code system where echo doesn't really fit (all echos appear above the main page nav on output). I like the more efficient coding system of the templates, and want to stick to it, but there are few examples documented. 

If I wrote them, do you think Ryan would be willing to add some more output examples to the docs?

Link to comment
Share on other sites

I have seen the repeaters documentation, but one thing that is a stumbling block for me is that a lot of the output examples given in the docs use echo. But the templates use a better code system where echo doesn't really fit (all echos appear above the main page nav on output). I like the more efficient coding system of the templates, and want to stick to it, but there are few examples documented. 

If I wrote them, do you think Ryan would be willing to add some more output examples to the docs?

Whereas that's a valid point, I am not sure that would happen. The primary purpose of the main docs found in http://processwire.com/api/variables/ and http://processwire.com/api/selectors/ is to quickly and efficiently teach (new) users how to use the ProcessWire API with as little verbosity and complexity as possible. The examples there are necessarily short so as not to lose focus or inundate the user. In addition, there are so many ways for outputting PHP content, different people preferring different styles, that it would be difficult to cover them all. The most basic/ubiquitous is 'echo' :-).  For most people, whilst learning how to use the system also improves their PHP skills, I  would suggest that you would get much more from the system if you additionally went through some very, very basic PHP tutorials :D. I could suggest a few if you haven't already identified any. On the other hand, in the template files tutorial such as this one http://processwire.com/docs/tutorials/how-to-structure-your-template-files/ you see some more advanced coding styles. 

Edit

Beaten by @LostKobrakai - but you see we refer to the same thing...

Edited by kongondo
Link to comment
Share on other sites

Thanks @LostKobrakai and @Kongondo. 

I have indeed read the documentation of template files, but they don't really help me. 

The docs are useful in the sense that they show the easiest ways to get a processwire site working, but what they show goes against commonly agreed best practise. For example, 'direct output with includes' is written up in the docs as perfectly valid markup. But in the forums, I see people refer to this as completely evil and never to be done (just tried to find an example to link to and couldn't remember where I'd seen it - please correct me if this understanding of mine is wrong!).

So I ask myself, as a beginner, why would I learn crappy ways to start with?

For me, it is better to be awful at a best practise way of coding and struggle along, than to learn to depend on crappy php includes that I will eventually have to change if I want to respect myself as a php coder  ;)

Delayed output seems to make the most sense for my build, for a variety of reasons. The default templates use delayed output, and I'm happy to stick to that. I see no need to change my template files away from this system. I do see a need for me to improve my skills to use delayed output well!

Even if there are myriad ways to output php and it would be impossible to cover them all, I still think it would be valuable to show at least one example of output in a format that worked with the intermediate template files. And I'm still volunteering to write the examples I have enough skill for!

And yes, I need some basic php tutorials to help learn PW better. Thanks again for encouragement and helpfulness. 

Link to comment
Share on other sites

RESOLVED

@Kongondo your code worked perfectly. Thank you! It was a relatively simple fix, but I had no idea how to do it myself. This makes me more resolved than ever to do some basic php tutorials. I'm going to start a new thread to ask for tutorial recommendations, as I'm sure a lot of people could benefit from it.

Link to comment
Share on other sites

My 2p....at the end of the day on such issues, really, it is horses for courses. There is nothing 'evil' about liberally using echo. Some people will include HTML in their PHP others will do it the other way round. Some people want complete separation of logic and 'views', others don't care. Some people use cameCase variables others don't. Some people swear by double quotes others prefer single quotes. Some people like OOP others prefer procedural style...Some people like direct output others prefer delayed. Others like template engines others don't...and on and on...

Tell you what, the only thing you should never ever compromise on is security; for that, there are no ifs or buts. As for coding style, just pick what you are comfortable with and makes you most efficient. However if collaborating on a project where there are multiple coders, then obviously you would need to agree on the coding style :D.

Edit:

Glad the code worked for you.

PHP resources: There's a number of threads on that already. Best if you searched first. I'll update this post if I can find the links as well. :-)

OK, here's some links:

https://processwire.com/talk/topic/2994-learning-php/

https://processwire.com/talk/topic/1555-learning-oop/ - more links in post #10 in that thread

https://processwire.com/talk/topic/6030-learning-php-where-to-learn-just-enough-to-make-living-w-pw-easier/

https://processwire.com/talk/topic/4439-when-do-we-need-curly-brackets/

https://processwire.com/talk/topic/1931-recommended-php-style-guide/

Happy coding!

Edited by kongondo
Link to comment
Share on other sites

(...) than to learn to depend on crappy php includes that I will eventually have to change if I want to respect myself as a php coder  ;)

Maybe your includes are crappy, but I love my includes :P

Link to comment
Share on other sites

@diogo Yes, my php includes are definitely crappy :) No offense intended. I'm glad to discover I had an incorrect impression of them. 

@Kongondo thanks for the list. If you are able to delete the new thread I created looking for tutorials (before I read your thread), please do so. This was a classic case of 'searching from within PW instead of google returned no results'. Reminds me to search the forums from google ALWAYS. :)

  • Like 1
Link to comment
Share on other sites

No offense taken :)

I'm not a great programmer, I'm more a designer-that-get-things-working and I feel very comfortable with using includes. My code looks so cozy between a include('header') and a include('footer') that I never had the urge to change how I do things.

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

×
×
  • Create New...