views:

73

answers:

4

I guess simple answer to the question would be a component.

Although I agree, I feel weird having to write a component for something so specific.

For example, let's say I have a table of users. When a user is created, it should form a chain reaction of events, initiating different kinds of data related to the user all around the database. I figured it would be best to avoid directly manipulating the database from different controllers and instead pack all that neatly in a method. However since some logic needs to be accesed separately, I really can't have the whole package in a single method. Instead I thought it would be logical to break it up to smaller pieces(like $userModelOrController->createNew() and $candyStorageModelOrController->createNew()) that only interact with their respective database table.

Now, if the logic is put to the model, it works great until I need to use other models. Of course it's possible, but when compared to loading models in a controller, it's not that simple. It's like a Cake developer telling me "Sure, it's possible if you want to do it that way but that's not how I would do it".

Then, if the logic is put to the controller, I can access other models really easy through $this->loadModel(), but that brings me back to the previously explained situation since I need to be able to continue the chain reaction indefinitely. Accessing other controllers from a controller is possible, but again there doesn't seem to be any direct way of doing so, so I'm guessing I'm still not doing it right.

By using a component this problem could be solved easily, since components are available to every controller I want. But like I wrote at the beginning, it feels awkward to create a component specifically for this one task. To me, components seem more like packages of extra functionality(like the core components) and not something to share controller-specific logic.

Since I'm new to this whole MVC thing, I could've completely misunderstood the concept. Once again, I would be thankful if someone pointed me to the right direction :)

A: 

It is deifinitley bugging that CakePHP does not support easly

  • accessing another Model from a Model
  • accessing a Component from a Model
  • accessing any Model from a Component
  • having a function accessible both from Controllers and Views (something between Components and Helpers), or accessing a Component from a Helper (or vica-versa)

I mostly ended up adding function to the superclass AppController.

sibidiba
If you're just trying to get at the methods of a model (ie. for idempotent behavior), what's wrong with App::import? Same goes for accessing a component / model from something else. If it's not idempotent, you're probably violating MVC, which is fine, but just know which scenario it is.
Travis Leleu
@sibidiba Glad to see I'm not the only one :) I also though about AppController, but I wanted to keep it clean, so I went with App::import.@Travis App::import one way to do things, but when the developers of CakePHP have paved the way so well for us, one might easily think that having to construct an object yourself is not the way it should go. After all - if you ask me - Cake's level of abstraction is insanely high. Since I started with Cake a year or so ago, I've never had to use the 'new' keyword in a CakePHP environment until now :)
Pichan
If you use `ClassRegistry::init()` instead of `App::import()`, you can continue not using the `new` keyword. :-)
Rob Wilkerson
@Travis: This has nothing to do with idempotency. Just assume you want to log into the database. Where do you put this? In a Model, you can't call it from another Model. Is it in a Component, it won't be able to access the log Model itself. Is it in AppContoller and you make it accessible to every Controller. It is a missing feature, not being able to use a Model within another Model or Component.
sibidiba
Huh? You can associate models to make them accessible. Or you can always get an instance of a model, anywhere, with `ClassRegistry::init('MyModel')`. You *shouldn't* do this in Components for proper MVC separation, but you *can*.
deceze
@Rob Thanks, I actually completely forgot about `ClassRegistry::init()` :) Though it still isn't _the_ answer I'm looking for here :)@deceze Hi again, am I being a nuisance? :D I know you can do everything with Cake that you can do with plain PHP. The thing I'd like to know is why it isn't proper MVC and how can I do it right? I'm still learning, so I'd like to start with doing things right and later derive from the safe path when I know which gears I shouldn't touch :)
Pichan
@deceze: Often I need a Model that is not associated. Consider the example of logging. Like you have a User::newUser() in your model that wants to log. `ClassRegistry::init('MyModel')` works of course, but seems like a hack in the code. Why not having a $uses, $componenets etc. variables anyhow. MVC in a niche concept, but IRL you rarely stick to it 111%.
sibidiba
For logging, which is a shared functionality of all models, you should create a Behavior, which internally can use a model (with `ClassRegistry::init`). I agree that 111% MVC is hard sometimes, but the more you stick to it, the better off your application in the long run. There's always some way to do it right-ish, and your complaint about models is simply not true. :)
deceze
I have to agree with deceze with. Logging is something that is usually shared application-wide, so it's logical to put the functionality in a behavior or component. In some special occasions I might even consider putting it in AppModel or AppController.
Pichan
Not to mention that logging is already part of almost every object with the 'log' function. :P
deceze
I haven't looked much into Cake's own logging, but I have the impression that it's mainly for debugging and tracking major events.My next project will involve logging users' actions to database and my tentative plan is to use behaviors for that.
Pichan
@deceze thanks for stepping in. I've never played much with behaviors, but after rereading that section of the manual, that's definitely the way to go. Agreed on the 111% MVC comment -- whenever I break MVC I try to make sure I know why I'm breaking it (and it's not usually, "Cake can't do it"). Thx again for your expertise.
Travis Leleu
A: 

It is clearly stated in the cookbook: "Components are packages of logic that are shared between controllers. If you find yourself wanting to copy and paste things between controllers, you might consider wrapping some functionality in a component."

bancer
Yeah, but Components do not support Models.
sibidiba
That is also covered in the manual: `$userInstance = ClassRegistry::init('User');` It is not recommended though. http://book.cakephp.org/view/996/Creating-Components
bancer
@bancer Yes, it is stated very clearly. So clearly even that I'd say it's a generalization and you shouldn't take it literally. I think that applies mainly to packages of logic, just like the core components.
Pichan
A: 

You can use the AppModel if you want your models to share some logic. If you need to access different models in your model, you can use App::import() or ClassRegistry::init. Now if you want the logic to be available only to some models of your choice, you can use a Behavior or create a different AppModel where only your selected models will inherit.

Gian Basagre
I don't think AppModel is the optimal place for this. For now, `App::import()` and `ClassRegistry::init()` have been the closest to achieving my goals with some grace, although I keep hearing it isn't really proper MVC.I'm also against components and behaviors, since it wouldn't just feel right to have methods like `activateUser`or `createUser` separated from the model or controller they belong to. I'm waiting for someone to convince me otherwise :)
Pichan
A: 

Probably a better way to implement this is within a plugin. Plugins allow you to encapsulate entire functionality across all parts of MVC into a package which can be pulled in anywhere in your code via the plugin's Helpers, Components, Behaviors. This way,

  • you can put the functionality where its most appropriate,
  • the logic is kept separate from the rest of your app logic and
  • you can enable/disable this functionality as needed.
Michael