Well I didn’t quite get my first webapp done in time for last week’s meeting. Actually I got it mostly working, but the interface was not to my liking and I wasted a lot of time flailing about trying to figure out how to do what I wanted. I finally figured out how to do that so it shouldn’t be much longer before I have things completed.
Basically the issue is that I want to enter sales data for each day and each store. Each day has some data associated with the day over all, and then it also has breakdowns of specific data on an hourly basis. Or in CakePHP model lingo, stores hasMany dailies hasMany hourlies. The problem is that I want to view (index), add and edit the daily AND hourly data together on one form. The alternative is to enter the daily data, then add an hour, enter than data, add an hour… ad nauseum. There’s a limited and known amount of hourly data to enter, so it would be much easier to get it all over and done with in one form.
Getting the view to show dailies and hourlies together was straightforward. The scaffolding did a decent job of that by default so I was able to bake the scaffold view and modify it to my preference. The default data structure will automatically load the daily and related hourly data together when using the appropriate data loaders on properly associated models.
The editing/adding was a bit stickier. CakePHP’s form helper doesn’t handle this kind of thing at all currently. Basically if you aren’t editing a single row in a single table, you’re on your own, bub. The breakthrough was in finding this post on cake.php. It’s not exactly what I wanted, but it set me on the right track. The difference is they are editing multiple records from the same table together while I want to edit a single record from one table and multiple records from a related table together.
Fortunately the principle in both cases is similar. In my case I started with modifying the edit controller/view first. All the records I want to modify already were getting loaded automatically since the models had the proper associations set up. In my view I had to just loop over individual hours and set up form entries for each of them. Hour and id are hidden since those should not be changed.
The core of the edit view code to do this is as follows:
<?php foreach (array_keys($this->data['Hourly']) as $key):?>
<tr>
<input type="hidden" name="data[Hourly][<?php echo $key; ?>][id]"
value="<?php echo $this->data['Hourly'][$key]['id']; ?>" />
<input type="hidden" name="data[Hourly][<?php echo $key; ?>][hour]"
value="<?php echo $this->data['Hourly'][$key]['hour']; ?>" />
<td><?php echo $pretty->hour($this->data['Hourly'][$key]['hour']);
?></td>
<td>
<input type="text" name="data[Hourly][<?php echo $key; ?>][hrtickets]"
value="<?php echo $this->data['Hourly'][$key]['hrtickets']; ?>" />
</td>
<td>
<input type="text" name="data[Hourly][<?php echo $key; ?>][hrgross]"
value="<?php echo $this->data['Hourly'][$key]['hrgross']; ?>" />
</td>
</tr>
<?php endforeach; ?>
It’s actually pretty straightforward conceptually, it was just getting the right incantation for it that was the problem, as this kind of thing is not covered in manual at all, and as mentioned, the forms helper doesn’t have code to do this kind of thing for you.
Then in the edit controller for dailies I originally had this (standard) code to save the modified data:
$this->Daily->save($this->data)
That will only save updates to the ‘Daily’ entries but not the ‘Hourly’ entries so I had to add:
foreach ($this->data['Hourly'] as $hourly) { $this->Hourly->save($hourly); }
This is a little bit simpler than the example in the above post. That’s because this is saving edits to existing data, so the ‘id’ field of each record is populated. In the add controller you need to do like the example in the post because the ‘id’ fields are empty in an add, so if you don’t create separate objects then the saves will just keep overwriting the first record over and over.
Anyways, the edit view and controller is already all set and working mostly the way I want it now. Getting the add view and controller working should be fairly simple at this point as that one is closer to the cake.php post I referenced. I might want to do something a bit fancy later by adding in forms for ‘missing’ hours in the edit, but that’s just spit and polish.
I’d be curious to know if the other MVC frameworks handle the case of adding/editing associated hasMany tables together in a more elegant manner?