Jump to content

efiguerola

Members
  • Posts

    14
  • Joined

  • Last visited

Community Answers

  1. efiguerola's post in Repeater won't save repeater items added programmatically was marked as the answer   
    -----------------------------------------------------------------------------------
    [WARNING] This is a long post. Sorry about that.
    -----------------------------------------------------------------------------------
    I solved this, so might as well post the details here. There *is* some weird ProcessWire behavior going on, but first things first.
    1. I didn't create the repeater field correctly (oops).
    As a part of the installation process for my module, I had to programmatically create a template which had a repeater as one of its fields. Now, I had a hard time finding documentation on how to do this exactly, and eventually I found a forum post that kinda helped me (here), but it would seem like it was missing some key steps needed in order to properly create a repeater field programmatically (perhaps due to it being an old post). I learned about those extra steps in another forum post (specifically, this one).
    2. The repeater field table was receiving duplicate values for the ID of the first repeater item (a bug, perhaps?)
    So I fix the installation code, do a clean PW install, then install my module again. Everything works, beautiful. Except... I was checking out the table PW created for my repeater field, and I noticed something weird going on. Initially, I create a page using the template that has this repeater field. A new row is created on the repeater field table in the database. At this point there are no existing repeater items added to the repeater, so the row looks like this:

    The "data" column stores a comma-separated list of the IDs of every single repeater item owned by the repeater. The "count" column stores the amount of repeater items that the repeater owns. At this point, zero.
    However, when I added some items to the repeater using the interface I built for my module (a form receives the user input and stores it using the API, as per the Repeaters documentation), the ID of the first repeater item (and only the first one) appeared twice on the "data" column of the repeater field table. This also meant the "count" column had a value of [real amount of items + 1]. So, for example:

    In order to solve this issue, I had to do something in my code that I think shouldn't be necessary, but I needed it to work well, so...
    Regarding the code that saves the repeater/repeater items, I had to change it from this:
    public function processForm() { // Get the data sent with the form and sanitize it before using it. /*-OMMITED FOR BREVITY-*/ // Channel ID validations. /*-OMMITED FOR BREVITY-*/ // Get the channel object (a page). /*-OMMITED FOR BREVITY-*/ // TV Grid data validations. /*-OMMITED FOR BREVITY-*/ // We need to clean this channel's grid before working with it. /* channel = Page tvChannelGrid = Repeater field tvChannelGridShow, tvChannelGridShowDay, tvChannelGridShowDuration, tvChannelGridShowRow = Repeater fields */ if(count($channel->tvChannelGrid) > 0) { $channel->tvChannelGrid->removeAll(); // Remove all repeater items. $channel->save("tvChannelGrid"); // Save the repeater. $channel->save(); // Save the page. } // Add the grid items received from the module's form to the channel's grid. foreach($tvGridData as $i => $item) { $showId = intval($item["tv_show_id"]); $duration = intval($item["duration"]); $day = intval($item["col"]); $row = intval($item["row"]); // Create a new item and add it to the repeater. $gridItem = $channel->tvChannelGrid->getNew(); // New repeater item // Assign values to repeater item fields. $gridItem->tvChannelGridShow = wire("pages")->get($showId); $gridItem->tvChannelGridShowDuration = $duration; $gridItem->tvChannelGridShowDay = $day; $gridItem->tvChannelGridShowRow = $row; $gridItem->save(); // Save the newly built repeater item. $gridItem->of(false); // Recommended in a forum post while trying to solve the issue. $channel->tvChannelGrid->add($gridItem); // Add repeater item to repeater. } if(count($tvGridData) > 0) { // We clearly received some new items, so let's save our work. $channel->save("tvChannelGrid"); // Save the repeater. $channel->save(); // Save the page. } return "<h2>TV Grid processed.</h2><p><a href='" . $this->page->url . "?channelId=$channelId'>Go back to the TV Grid Editor.</a></p>"; } ...to this:
    public function processForm() { // Get the data sent with the form and sanitize it before using it. /*-OMMITED FOR BREVITY-*/ // Channel ID validations. /*-OMMITED FOR BREVITY-*/ // Get the channel object (a page). /*-OMMITED FOR BREVITY-*/ // TV Grid data validations. /*-OMMITED FOR BREVITY-*/ // We need to clean this channel's grid before working with it. /* channel = Page tvChannelGrid = Repeater field tvChannelGridShow, tvChannelGridShowDay, tvChannelGridShowDuration, tvChannelGridShowRow = Repeater fields */ if(count($channel->tvChannelGrid) > 0) { $channel->tvChannelGrid->removeAll(); // Remove all repeater items. $channel->save("tvChannelGrid"); // Save the repeater. $channel->save(); // Save the page. } // Add the grid items received from the module's form to the channel's grid. foreach($tvGridData as $i => $item) { $showId = intval($item["tv_show_id"]); $duration = intval($item["duration"]); $day = intval($item["col"]); $row = intval($item["row"]); // Create a new item and add it to the repeater. // FOR SOME REASON (), creating a variable here, storing the new grid item // inside said variable, and then passing the variable to the repeater's "add" // function as a parameter, causes the first repeater item's ID to be duplicated // in the repeater field's table (repeater field row, "data" column; also, wrong // repeater item count in "count" column). $channel->tvChannelGrid->add($this->createGridItem(array( "showId" => $showId, "duration" => $duration, "day" => $day, "row" => $row, ), $channel->tvChannelGrid)); } if(count($tvGridData) > 0) { $channel->save("tvChannelGrid"); // Save the repeater. $channel->save(); // Save the page. } return "<h2>TV Grid processed.</h2><p><a href='" . $this->page->url . "?channelId=$channelId'>Go back to the TV Grid Editor.</a></p>"; } function createGridItem($data, $grid) { $gridItem = $grid->getNew(); $gridItem->tvChannelGridShow = wire("pages")->get($data["showId"]); $gridItem->tvChannelGridShowDuration = $data["duration"]; $gridItem->tvChannelGridShowDay = $data["day"]; $gridItem->tvChannelGridShowRow = $data["row"]; $gridItem->save(); // Save the newly built item. $gridItem->of(false); return $gridItem; } At first I thought: "Okay, the problem seems to be that I need to isolate the piece of code that creates the new repeater item inside a separate function", but then I realized that's not quite it. That is because, even if I isolated that piece of code inside a different function, the problem still occurred if I created a variable ($gridItem) inside the foreach loop that stored the output of the createGridItem function.
    In the end, I had to pass the output of the createGridItem function directly to the repeater's add function, without storing it inside a variable first.
    Hmm, so I guess there is a tl;dr:
    (*) We need rich, readily available documentation for backend development / module development / doing things with code and not via GUI, in the same way we have awesome documentation for the frontend (pages, templates, API usage) aspect of PW. I think forum posts are great for solving specific issues, or maybe expanding on lesser known aspects of something, but they shouldn't be the primary source of information, there should be documentation pages for that.  (**) Apparently, I cannot have a variable that stores a new repeater item inside a foreach loop, or PW does weird stuff.  (*) Do note that I am not in any way demanding this happens, I'm merely making a suggestion.
    (**) If you notice I did some dumb mistake, point it out... I don't think so, but just in case... hahahaha.
×
×
  • Create New...