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!

+1


a source to share


2 answers


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
}

      

+3


a source


I know this is an old question, but it looks like an ACL component would be a good option.



0


a source







All Articles