Skip to content

Commit 9c1e933

Browse files
committed
Fully document polymorphic uploads. Closes FriendsOfCake#94. Closes FriendsOfCake#124
1 parent b47ea3b commit 9c1e933

File tree

1 file changed

+75
-0
lines changed

1 file changed

+75
-0
lines changed

README.markdown

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,81 @@ We would also need a similar relationship in our `Message` model:
246246
);
247247
}
248248

249+
Now that we have our models setup, we should create the proper actions in our controllers. To keep this short, we shall only document the Post model:
250+
251+
<?php
252+
class PostsController extends AppController {
253+
/* the rest of your controller here */
254+
public function add() {
255+
if ($this->request->is('post')) {
256+
try {
257+
$this->Post->createWithAttachments($this->request->data);
258+
$this->Session->setFlash(__('The message has been saved'));
259+
} catch (Exception $e) {
260+
$this->Session->setFlash($e->getMessage());
261+
}
262+
}
263+
}
264+
}
265+
266+
In the above example, we are calling our custom `createWithAttachments` method on the `Post` model. This will allow us to unify the Post creation logic together in one place. That method is outlined below:
267+
268+
<?php
269+
class Post extends AppModel {
270+
/* the rest of your model here */
271+
272+
public function createWithAttachments($data) {
273+
// Sanitize your images before adding them
274+
$images = array();
275+
if (!empty($data['Image'][0])) {
276+
foreach ($data['Image'] as $i => $image) {
277+
if (is_array($data['Image'][$i])) {
278+
// Force setting the `model` field to this model
279+
$image['model'] = 'Post';
280+
281+
// Unset the foreign_key if the user tries to specify it
282+
if (isset($image['foreign_key'])) {
283+
unset($image['foreign_key'])
284+
}
285+
286+
$images[] = $image;
287+
}
288+
}
289+
}
290+
$data['Image'] = $images;
291+
292+
// Try to save the data using Model::saveAll()
293+
$this->create();
294+
if ($this->saveAll($data)) {
295+
return true;
296+
}
297+
298+
// Throw an exception for the controller
299+
throw new Exception(__("This post could not be saved. Please try again"));
300+
}
301+
}
302+
303+
The above model method will:
304+
305+
- Ensure we only try to save valid images
306+
- Force the foreign_key to be unspecified. This will allow saveAll to properly associate it
307+
- Force the model field to `Post`
308+
309+
Now that this is set, we just need a view for our controller. A sample view for `View/Posts/add.ctp` is as follows (fields not necessary for the example are omitted):
310+
311+
<?php
312+
echo $this->Form->create('Post', array('type' => 'file'));
313+
echo $this->Form->input('Image.0.attachment', array('type' => 'file', 'label' => 'Image'));
314+
echo $this->Form->input('Image.0.model', array('type' => 'hidden', 'value' => 'Post'));
315+
echo $this->Form->end(__('Add'));
316+
?>
317+
318+
The one important thing you'll notice is that I am not referring to the `Attachment` model as `Attachment`, but rather as `Image`; when I initially specified the `$hasMany` relationship between an `Attachment` and a `Post`, I aliased `Attachment` to `Image`. This is necessary for cases where many of your Polymorphic models may be related to each other, as a type of *hint* to the CakePHP ORM to properly reference model data.
319+
320+
I'm also using `Model.{n}.field` notation, which would allow you to add multiple attachment records to the Post. This is necessary for `$hasMany` relationships, which we are using for this example.
321+
322+
Once you have all the above in place, you'll have a working Polymorphic upload!
323+
249324
Please note that this is not the only way to represent file uploads, but it is documented here for reference.
250325

251326
### Alternative Behaviors

0 commit comments

Comments
 (0)