How can I do this without breaking the MVC framework in CakePHP?
Sorry for the general title. I am not the best of titles.
Anyway, the way Cake passes the data (as a hash) is pretty much the reason why I even need to ask this question. If, when I passed the / obj variable from controller to view, it was an object that I could set (e.g. $ duck-> quack ()) instead of being an array / dictionary (i.e. $ duck ['Duck'] ['quack'] == true), that would be easy.
What I have in my application is a list of items that user x can own or not. In some views, I display all items in the database / application (like paginate), and for every item I need to know if a logged in user belongs to it or not. To answer this question, I need to make a query (due to the complex HABTM relationship) that is executed inside the model. In other words, my Item model has an isOwnedByUser ($ user_id, $ item_id) function that is true if it belongs to the user. I want to call this function from a view.
Naturally this breaks the MVC framework, but I'm not sure how to do it. I had four ideas:
Idea 1:
Do it inside the helper:
App:Import('Model','Item');
$item = new Item();
$item->isOwnedByUser($user_id,$item_id);
and call the helper from the view (and of course go to $ item_id and $ user_id). But it DOES break the MVC framework.
Idea 2:
Create an action inside item_controller.php and call the action from the view using requestAction (). But I heard it was extremely ineffective
Now these two ideas that I found when I was looking for a solution to my problem, but according to them, these two ideas are bad, so I came up with two more solutions:
Idea 3:
When returning the paginated data to the view, I can ensure that all items have a "user_id" key so that I can check the key in the view from the registered user id to see if the item belongs to it. But that would require: a) me to rewrite the pagination; b) very ugly queries, especially for certain species (search), c) general ugliness and slowness. So I decided to give up this idea.
Idea 4:
Every time the view needs to know if an item is owned by the user, I just pass another array from the controller that contains ALL the items the user owns, and in the view you can simply use in_array () to check if the user owns the specified item. Of course, the problem with this is obvious: what if the user has many items?
In short, I am stuck with this and I have no idea where to go from here and I would appreciate any help! Thanks!
a source to share
I would combine 3 and 4.
In its action, after getting all the paginated items:
$items = $this->paginate('Item');
Get your IDs and combine them with your user ID to get all custom items.
$itemIds = Set::extract('/Item/id', $items);
$usersItems = $this->Item->User->find
(
'all',
array
(
'conditions' => array
(
'User.id' = $userId,
'Item.id' => $itemIds
),
'fields' => array('User.id', 'Item.id')
)
);
Now you can set $ usersItems in the format you prefer and set both this and $ items for the view. This will take you to your options 4 and in_array (), except that it will probably be Set :: extract () or Set :: check ().
Something like this should do it:
if (Set::extract(sprintf('/Item[id=%s]', $itemId), $usersItems))
{
// user has the item
}
(I wrote this from my memory, so ... you know what to do if it fails :))
Edit:
Alternatively, you can do something like this (it should be faster than the above, just move Set::extract()
out of the loop):
$usersItemIds = Set::extract('/Item/id', $usersItems);
if (in_array($itemId, $usersItemIds))
{
// user has the item
}
a source to share