0

For clarity consider a fairly standard "User registration" functionality:

My ORM (Propel) allows you to alter the class ormUser, which extends the ormUserBase, in order to introduce custom functionality.

Now that I have coupled Propel with an MVC framework I am wondering which logic should go where from a best practice point of view.

For my user registration functionality I'd create:

  • RegistrationController - which uses the

  • UserModel - which in turn should call something like

  • LoginView
  • LogoutView
  • SignupView
  • ProfileView

The user database table is coupled with user-profile and Propel has generated handy methods to work with these tables. But now Propel's standard methods are not sufficient and I need to extend functionality.

Where would one do this correctly?

Would I only extend ormUser for new query methods and place non-query logic in my UserModel? Or would you simply ignore ormUser and use UserModel for everything custom, calling other ormTableNameClass-s there as needed for my logic?

I understand keeping new methods in Propel has the benefit of reusability in other Models and Controllers, but I'm not sure from a "do it correctly" point of view since it seems I need business logic to determine the outcome of certain queries.

UPDATE: Using ORM classes directly from the controller in MVC, bad practice? shows how one usually works with Propel, which in my mind overlaps the framework's model...

Community
  • 1
  • 1
MattW
  • 538
  • 1
  • 4
  • 12
  • It depends on the type of functionality you want to add. Can you give an example? – Jan-Henk Oct 14 '11 at 10:49
  • Sure - say I'd want to create a public "show users profiles alphabetically" view. I would need paging logic and multiple queries, most of which are native to Propel but lets assume here they are not fully covered. Let's say I need logic in the queries itself which is not DB related. Would I create a method in Propel that takes arguments for the paging, executing this method from my Model and working, or would I do it all in my Model? – MattW Oct 14 '11 at 14:10
  • In that scenario the controller should retrieve a list of alphabetically ordered user models, and pass this list to the view. The view then constructs the HTML output of the actual list of user profiles. I do not know how Propel works, but you should not add the retrieval logic to the user model. Ideally you would create some sort of user repository class that interfaces with Propel, and that class would be responsible for retrieving user objects from the database. – Jan-Henk Oct 14 '11 at 14:33
  • Thanks - the confusion exists because the ORM (Propel) offers the extending of their (generated) base CRUD classes. In framework terms those are more or less already a Model,, or at least fullblown getters/setters with a twist (validations etc). If I understand you correctly it would perhaps better/cleaner to have my frameworks UserModel extend Propel's ormUser- so I have all the CRUD and can extend it if needed? – MattW Oct 14 '11 at 15:52
  • Yes indeed. Maybe it will be helpful if you take a look at the symfony jobeet tutorial http://www.symfony-project.org/jobeet/1_4/Propel/en/. I just remebered that I skimmed through this tutorial a while back, but it is a nice example of how a MVC framework and an ORM can work together. You can just focus on the controrller and model chapters. I skimmed through the Doctrine version of this tutorial, but the link is to the Propel version. How up-to-date this tutorial is for the current version of Propel I don't known tough. – Jan-Henk Oct 14 '11 at 16:06
  • Thanks Jan-Henk - I have updated my question with a link that shows nicely where Propel-models overlap framework models. – MattW Oct 14 '11 at 16:09

1 Answers1

0

I come at this from having paired Propel with symfony 1.0 for several years. Perhaps I've not understood your post fully, but I am unsure what you think is missing from Propel.

For clarity, the thing you call a model, I would call "business logic" or an "action". The model, at least the way I understand the jargon, is the database and the class layer on top of the database. Your "views" are IMO still part of the logic/action section of MVC. I would regard a view as officially referring to something different: the output layer that renders the output of an action.

In Propel, you basically have three classes for each table: row, peer, and query (historically Propel users have got used to two, since query is new). The row is simple - just a class representation of a database row. The peer is for table-wide operations such as selecting several rows, and the query class is a new chainable API to run statements on the database.

So, in each of your actions (login, logout, etc) you should call Propel to do the necessary work. Where you find you have a large chunk of code in your action, in most cases it can be refactored into a Propel row or peer. This fits in with the MVC rule of thumb "thin controllers, fat models" i.e. try to keep your db stuff in the controller slim.

How you should structure your project depends on your framework, but I would show it like this:

    RegistrationController - which uses the

    UserAction - which in turn should call something like

    LoginAction (rendered by LoginView)
    LogoutAction (rendered by LogoutView)
    SignupAction (rendered by SignupView)
    ProfileAction (rendered by ProfileView)

    - each of which access the model UserModel
halfer
  • 19,824
  • 17
  • 99
  • 186
  • Can you please elaborate on how the UserAction / OtherActions relate to eachother and the Propel classes? I'm not sure I understand but I am fairly certain they are NOT Propel generated classes but build the Propel objects and work with those, returning results to the Controller? – MattW Oct 17 '11 at 10:23
  • Correct, the Action and View elements are part of your framework, rather than part of the ORM. Some use cases can be generated by frameworks - I believe these are called "scaffolds" (Rails) or "admin generators" (symfony). They are usually only for list-detail views on a particular table (e.g. "Orders"). For all of the use-cases you have here, I think you would manually write those files. (Addendum: if you run through an MVC tutorial, the delineations between the various parts of the trilogy will become much clearer. Jobeet is excellent but is only for an older version of symfony.) – halfer Oct 17 '11 at 13:50
  • So UserAction is acting as an in-between layer between the Controller and the actual Actions it can call; it represents the gateway to all User-related Actions within the Registration realm. The SomeAction has all the business logic and makes use of Propel. Propel deals with the actual Model, the database in this case. Cool, I understand now I think :) - thank you. – MattW Oct 17 '11 at 19:54
  • Yes, that's right. UserAction could be a class (extended by the specific action classes) containing code that is common to all of them. Or, it could just be a directory containing the actions, and in fact each of them are called directly by RegistrationController. Implementations will vary. The important point is that in MVC terms, the RegistrationController and the five Action items we're discussing are all parts of the "C", the Controller. How they are split up is down to the specific framework. – halfer Oct 17 '11 at 20:26