SitePoint Sponsor

User Tag List

Page 1 of 2 12 LastLast
Results 1 to 25 of 26
  1. #1
    SitePoint Guru
    Join Date
    May 2003
    Location
    virginia
    Posts
    988
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    Class Methods as Request Actions in MVC

    I recently checked out Ismo and liked the idea of having a class, that handled requests, that were all related to the model/application. A lot of times, I have action classes that have a few lines, and it's more of a pain to open them up and change things. With all of them in the same class, it seem like it would be easier to handle small to medium sized classes (action groups).

    I built my own mini version, that handles views differently. Each action returns the type of view (success, init, fail etc...), the application controller intreprets it, and loads the correct view class. But the view class is set up the same way. It's a class that uses it's methods for the different types of views. so if your action class was called 'ProductAdmin_controller', and returned a view of 'add_success', the view class would be 'ProductAdmin_viewer' and the method in the view class would be 'view_add_success()'. I really like the way it all feels, and it's easy to see what's going on throughout the code.

    Does this present any problems that I'm not seeing? How would you handle alternative content using this method?

    Matt

  2. #2
    SitePoint Guru dagfinn's Avatar
    Join Date
    Jan 2004
    Location
    Oslo, Norway
    Posts
    894
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by mwmitchell
    I recently checked out Ismo and liked the idea of having a class, that handled requests, that were all related to the model/application. A lot of times, I have action classes that have a few lines, and it's more of a pain to open them up and change things. With all of them in the same class, it seem like it would be easier to handle small to medium sized classes (action groups).

    Matt
    I've also used what you call "action groups", and I like it. It's easy to refactor. Typically related commands will have some duplicated code, and you can deal with that by extracting methods and classes.
    Dagfinn Reiersøl
    PHP in Action / Blog / Twitter
    "Making the impossible possible, the possible easy,
    and the easy elegant"
    -- Moshe Feldenkrais

  3. #3
    SitePoint Member
    Join Date
    Jan 2004
    Location
    Bologna (ITALY)
    Posts
    7
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    hi, i'm interested in what you say...

    will you paste here an example, please?

    tnx.

  4. #4
    SitePoint Zealot prefab's Avatar
    Join Date
    Jan 2003
    Location
    Belgium
    Posts
    133
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Being involved in the development of Ismo, I would suggest the following approach: create your Ismo_Core_State_HTTP as usual. I think it might not be clear from the current documentation (it's being rewritten: http://ismo.sourceforge.net/manual/), but if your execMethod returns a string that corresponds to a show<string> method within the state, that view is executed (of the view returns a string also, show<string> is executed recursively: showHeader > showBody > showFooter). You pass your model to the view indirectly to the view through a property.

    To further use the Ismo state approach, you can now take advantage of pre- and post- methods (see docs), which let you add a usefull common layer to a baseState for example. On top of that, we're working on an AOP like approach where you can have specific aspects and global aspects.

    - prefab

    PHP Code:
    <?php

    require_once('Ismo/Core/State/HTTP.php');

    class 
    example extends Ismo_Core_State_HTTP
    {

        var 
    $nsModel// the model property

        
    function example()
        {
            
    parent::Ismo_Core_State_HTTP();
        }

        function 
    execDefault()
        {
            ....
            ....
            return 
    'welcome';
        }

        function 
    showWelcome()
        {
            echo 
    "<h1>Welcome</h1>";
        }

        function 
    execEdit()
        {
            ....
            ....
            ....
            return 
    'success';
        }

        function 
    showSuccess()
        {
            echo 
    "<h1>Done</h1>";
        }



    ?>
    Now, if you were to use seperate view classes instead, one could do this:

    PHP Code:
    <?php

    require_once('Ismo/Core/State/HTTP.php');
    require_once(
    'Ismo/Core/View/Loader.php'); // pseudo code

    class example extends Ismo_Core_State_HTTP
    {
        
        var 
    $nsModel;

        function 
    example()
        {
            
    parent::Ismo_Core_State_HTTP();
        }

        function 
    execDefault()
        {
            ....
            ....
            return 
    'welcome';
        }

        function 
    execEdit()
        {
            ....
            ....
            ....
            return 
    'success';
        }

        function 
    _showMethodMissing($name// overrides the basic method saver
        
    {
            
    // this is not ready yet, so pseudo code ahead
            
    $view = &Ismo_Core_View_Loader::factory($this->_stateName);
            if(
    is_object($view) && is_a($view'ismo_core_view_plain')) {
                    
    $view->setModel($this->nsModel); // hand over the model
                    
    $view->execute($name);
            }
        }



    ?>

    <?php

    require_once 'Ismo/Core/View/Plain.php';

    class 
    exampleView extends Ismo_Core_View_Plain {

            function 
    showWelcome() {
                    echo 
    '<h1>Welcome</h1>';
            }

            function 
    showSuccess() {
                    echo 
    '<h1>Done</h1>';
            }

    }

    ?>

  5. #5
    SitePoint Guru
    Join Date
    Oct 2001
    Posts
    656
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    What you are saying does not go against the MVC principle. However, I think that it looks very 'procedural', you could hardly call it really object oriented.

    Ismo_Core_State_HTTP subclasses are really just a namespace with functions disguised as an object with methods. For large 'action groups', there could be a dozen or more exec_myaction() methods, one for each action of the application. That means that one class is trying to do way too much, it is bloated and it really is just a 'procedural class'.

    What is wrong with one object for each action of the application? Call it an Action or ActionController or whatever you want to call it. You gain the advantage of small and simple classes, you can use inheritance, composition, and all the other benefits of OOP. You can't do that with a class like Ismo_Core_State_HTTP.

    There are other ways to group "action groups" together.

    PS, the prodecural class thing is even an anti pattern, I just can't find the link for it..

  6. #6
    SitePoint Zealot prefab's Avatar
    Join Date
    Jan 2003
    Location
    Belgium
    Posts
    133
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Captain Proton
    What is wrong with one object for each action of the application? Call it an Action or ActionController or whatever you want to call it. You gain the advantage of small and simple classes, you can use inheritance, composition, and all the other benefits of OOP. You can't do that with a class like Ismo_Core_State_HTTP.
    I beg to differ. Ismo_Core_State_HTTP is more than a 'namespace' for grouping actions together. Ismo_Core_State_HTTP extended classes are real classes and its instances are 'real' objects. This means you have all of the benefits of OOP at your disposal. In fact, the first thing you should do is subclass Ismo_Core_State_HTTP to setup your base state(s). From there you proceed with your specific logic. That way you have a common layer, which you usually require anyway. It allows you to share a certain behaviour throughout the state or even throughout any state you subclass.

    The goal is to use composition and inheritance to share behaviour while letting you override it if necessary. The key is to discern into which parts you should split and group that behaviour. That way you avoid states that try to do too much. With the new developments, it should become clear that the object nature of states is a powerfull, yet easy to use, concept.

    - prefab

  7. #7
    SitePoint Guru
    Join Date
    May 2003
    Location
    virginia
    Posts
    988
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Too me it still looks like OOP. But I find myself learning from people here everyday, always realizing that I don't know much. So this only my opinion and my way of thinking at this point.

    If you look at most examples/tutorials for OOP, they all use example, real world objects. Like the car example. The car example shows that each of the cars 'actions' are grouped within the car. If you want to go faster, you would ask the car to go faster. That's how I'm seeing the Ismo approach.

    With the other approach (a class for each action) it seems to me that you would call a ChangeSpeed object, that would ask the car to go faster. Which may be more clean and separated. But could be overkill depending on what you are doing. Right?

    I created an application last night that would allow you to CREATE a 'product', EDIT the product and DELETE. And of course VIEW all products. I had an action class for each one. And a view class for each one. That's 8 classes. It seemed like a lot of code, and I always feel proud to look lots of lines of code, that actually works and makes sense. But then I converted it all to the Ismo method, and I was amazed at how small it all was, and I could make sense of everything at once. It was so much easier to look at and read.

    But I still want to know what the possible side effects are? I mean I know with everything in life, there are trade-offs

    Matt

  8. #8
    eschew sesquipedalians silver trophy sweatje's Avatar
    Join Date
    Jun 2003
    Location
    Iowa, USA
    Posts
    3,749
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by mwmitchell
    I created an application last night that would allow you to CREATE a 'product', EDIT the product and DELETE. And of course VIEW all products. I had an action class for each one. And a view class for each one. That's 8 classes. It seemed like a lot of code, and I always feel proud to look lots of lines of code, that actually works and makes sense. But then I converted it all to the Ismo method, and I was amazed at how small it all was, and I could make sense of everything at once. It was so much easier to look at and read.
    BTW: The technically correct acronym to use when expressing this concept is CRUD (Create,Retrieve,Update,Delete)
    Jason Sweat ZCE - jsweat_php@yahoo.com
    Book: PHP Patterns
    Good Stuff: SimpleTest PHPUnit FireFox ADOdb YUI
    Detestable (adjective): software that isn't testable.

  9. #9
    SitePoint Guru
    Join Date
    Oct 2001
    Posts
    656
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I beg to differ. Ismo_Core_State_HTTP is more than a 'namespace' for grouping actions together. Ismo_Core_State_HTTP extended classes are real classes and its instances are 'real' objects. This means you have all of the benefits of OOP at your disposal. In fact, the first thing you should do is subclass Ismo_Core_State_HTTP to setup your base state(s). From there you proceed with your specific logic. That way you have a common layer, which you usually require anyway. It allows you to share a certain behaviour throughout the state or even throughout any state you subclass.
    Alright, but it is still comparable to a namespace, even though it subclasses are instanciated as real objects.

    But you cannot deny that Ismo_Core_State_HTTP is a class that basically has a function for everything that can be done with a part of the application's domain. Like sweatje says, it's responsible for the CRUD of something that is (usually) related to a single database table.

    Too me it still looks like OOP.
    Exactly, it looks like OOP and it is very easy to grasp the concept of how it works, because it is in fact procedural code disguised in a class and that is what most programmers are familiar with.

    When people coming from a procedural programming (PP) background and switch to OOP, they often group together a lot of functions from a procedural library into a class as methods. It seems logical and it is an easy conceptual step to make from the PP code to the OOP code, because the methods on that class areof an object look a lot like procedures. Because it looks so understandable when you relate it to PP, it seems like it is "the right thing".
    But then I converted it all to the Ismo method, and I was amazed at how small it all was, and I could make sense of everything at once. It was so much easier to look at and read.
    Like you said, you're new to OOP, and the structure of the code that you make in ismo looks very understandable and familiar, because you are thinking procedurally. That is not meant as an insult or anything, it's a very understandable thing in fact. When I first started to use some OOP in my scripts, I did the exact same thing. I created Modules, very comparable to Ismo's states, with methods like addNews(), editNews(), deleteNews(), listNews(), etc: CRUD objects. That lead to classes that sometimed spanned over 400 lines of code! Now that is by definition a bad code smell: one class trying to do waay to much, split it up into larger classes.

    If you split each ismo State with methods for each action into an Action object for each action, you will see that you will have lots of small classes that are focused on only one part of the CRUD. Of course there will be the problem of duplicated code at first. With Ismo's State classes, you can simply wrap this duplicated code inside a method on the State class that can be called by all action methods, if needed. Very easy to do, very logical but also very procedural. It's just like a library of PP code where one function calls another helper function to execute code that is common to more than one function.

    So how do you handle this when you want to split the large State class into multiple Action classes? You can either make smart use of inheritance or of object composition. Inheritance is the easiest solution. Say you have these classes: AddNewsAction, EditNewsAction, DeleteNewsAction, ViewNewsAction. AddNews and EditNewsAction have a lot of functionality in common, they must both insert or update to the database, validate the fields submitted via a form, etc. You could create a parent class for the AddNews and EditNews actions, like ManipulateNewsAction. This would be an abstract base class.

    Of course each CRUD section of your application will also have a lot of common behaviour. Each Add[something]Action will follow the same steps (validating, redisplaying form, saving to database, etc) so you can even create a base class for all add actions and one for all edit actions: BaseAddAction and BaseEditAction. Now, these classes will also have common functionality, like all Add and Edit actions, so you can create a parent class like BaseManipulateAction.

    Try doing something similar in Ismo without stuffing lots and lots of common methods inside parent God classes. It will lead to bloated classes that are responsible for way too many things.

    Just found something. This anti-pattern is called The Blob on [url=http://www.antipatterns.com/dev_cat.htm[/url]this site or God Class here.

    Well, I hope my attempt at convincing you has at least partially succeeded. In any case, I think it's always good to discuss things
    I once had a problem.
    I thought: "Oh, I know: I'll just use XML!"
    Now I had two problems.

  10. #10
    SitePoint Guru
    Join Date
    Oct 2001
    Posts
    656
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Here's an example that (I think) demonstrates how Ismo State objects are simply a library of functions disguised as an object.

    First here we have the procedural code. A file with a switch statements and a function responsible for each 'Action'. I believe this will look familiar to a lot of PHP programmers. It is how I structured my 'large' programs, with one of these files for each CRUD section of my application.
    PHP Code:
    function exec_add() { ..... }
    function 
    exec_edit() { .... }

    switch (
    $_GET['action'])
    {
        case 
    'add':
            
    exec_add();
            break;
        
        case 
    'edit':
            
    exec_edit();
            break;

    Now compare this with the way Ismo does this:
    PHP Code:
    /**
    * This class is basically the switch statement in the procedural example.
    * I know it does a lot of other important things
    * but those are not really important for proving my case
    **/
    class IsmoApplication
    {
        
    // Get a state object somehow
        
    $state = ...;
        
        
    // I know this is simplified, but it is the core of what's going on.
        
    $method 'exec_' $_GET['action'];
        
    $state->$method();
    }

    /**
    * This is the file responsible for a CRUD section, except that now it has got a
    * class statement around it.
    **/
    class SomeIsmoStateSubclass
    {
        function 
    exec_add() { ... }
        function 
    exec_edit() { ... }
        function 
    exec_whatever() { ... }

    See the similarity between the two?

  11. #11
    SitePoint Guru
    Join Date
    May 2003
    Location
    virginia
    Posts
    988
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Captain Proton,

    I do see what you are saying and I appreciate your input. This is exactly why I posted this topic

    So, the thing that I'm not sure about is how they can be 'god' classes when they are usually dealing with only one model. With only 3-4 methods. And so far, I see all of the signs of being object oriented. Inheritance, Polymorphism, Overriding methods, Composition. I would think that it would be more up to the programmer on whether or not it would be a bloated action class. And the same for whether or not the methods contain a lot of procedural code.

    In your example with the switch statement, that looks more like an example of a front controller possibly? In frameworks that have seperate action classes for each request, there is still that same logic happening somewhere within the front controller right? They are just calling a class method instead of a function (like in your example).

    Also, with these state classes, they are all working with class variables. For instance the same model is being manipulated via the methods. That's another sign of it being OOP right?

    Ha, I'm not sure if I should even being going out on a limb like this! But I figure this is the best way to learn. Also, I'm not sure if I was trying to figure out if this is OOP or not. I guess more if it presents any unforeseen problems. Regardless... Your arguments are valuable to me.

    Matt

  12. #12
    SitePoint Guru dagfinn's Avatar
    Join Date
    Jan 2004
    Location
    Oslo, Norway
    Posts
    894
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    (My comment are not based on Ismo, which I've only looked at briefly, but on my own "framework" which appears to be similar.)
    Quote Originally Posted by Captain Proton
    Alright, but it is still comparable to a namespace, even though it subclasses are instanciated as real objects.
    I agree with you that it's basically just a function library wrapped inside a class, but I don't necessarily think that's a bad thing. I don't think we should rule out the possibility that procedural code is sometimes the best solution.

    Quote Originally Posted by Captain Proton
    Like you said, you're new to OOP, and the structure of the code that you make in ismo looks very understandable and familiar, because you are thinking procedurally.
    I'm not new to OOP, and I still prefer it. Not because it looks familiar, but because I find it easy to refactor.
    Quote Originally Posted by Captain Proton
    With Ismo's State classes, you can simply wrap this duplicated code inside a method on the State class that can be called by all action methods, if needed. Very easy to do, very logical but also very procedural. It's just like a library of PP code where one function calls another helper function to execute code that is common to more than one function.
    Again, you're right that it's procedural, but that's OK by me if it's the simplest design that works. I'll extract classes from it, too, but only if the code is telling me to do so.

    Quote Originally Posted by Captain Proton
    So how do you handle this when you want to split the large State class into multiple Action classes? You can either make smart use of inheritance or of object composition. Inheritance is the easiest solution. Say you have these classes: AddNewsAction, EditNewsAction, DeleteNewsAction, ViewNewsAction. AddNews and EditNewsAction have a lot of functionality in common, they must both insert or update to the database, validate the fields submitted via a form, etc. You could create a parent class for the AddNews and EditNews actions, like ManipulateNewsAction. This would be an abstract base class.
    I admit I've never tried exactly this approach to this problem. But from your description it looks unnecessarily complex to me. It seems you are using inheritance and composition, and probably Template Method to do something which would be simpler with plain method calls.

    You see, I believe that when I start out with the quasi-OO class and refactor to remove duplication, I'll end up with a simpler design that if I add complexity to begin with by making all those classes. But I realize I won't be 100% sure until I try both with the same code and compare the two.
    Dagfinn Reiersøl
    PHP in Action / Blog / Twitter
    "Making the impossible possible, the possible easy,
    and the easy elegant"
    -- Moshe Feldenkrais

  13. #13
    SitePoint Member tyrak's Avatar
    Join Date
    Jan 2004
    Location
    Middle Finland
    Posts
    2
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    It seems to me that the approach Captain Proton advocates is the way the Struts framework (the leading Java web application framework, http://jakarta.apache.org/struts/) works. However, Ismo's design resembles more the WebWork framework (another not so leading Java framework, http://www.opensymphony.com/webwork/) which obviously makes it different.

    The major principle of WebWork is the ease of use, which makes it possible to be very productive right from the beginning. The small concentrated API is quick to grasp yet extendable and powerful when used correctly.

    It is hard to say which way is the better one as there are zealots in both camps arguing that theirs is the right one...

    It can be argued that the Struts approach is purer OOP, and that WebWork is more pragmatic. However, in my opinion idealistic OOP is something to aim for but good enough OOP can be a reasonable compromise.

  14. #14
    SitePoint Evangelist
    Join Date
    Dec 2003
    Location
    Arizona
    Posts
    411
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    The Struts Framework uses the Command Pattern as Captain Proton has described, however, Struts also has a class named DispachAction which is an Action class that has it's methods invoked via reflection. From the API documentation:

    This Action is useful for developers who prefer to combine many similar actions into a single Action class, in order to simplify their application design.
    It seems to me that the Command Pattern would appeal more to the OO purist and this method would appeal more to the procedural programmer.

    Here is a link if anyone is interested: http://jakarta.apache.org/struts/api/index.html.

    JT

  15. #15
    SitePoint Guru dagfinn's Avatar
    Join Date
    Jan 2004
    Location
    Oslo, Norway
    Posts
    894
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by prefab
    To further use the Ismo state approach, you can now take advantage of pre- and post- methods (see docs), which let you add a usefull common layer to a baseState for example. On top of that, we're working on an AOP like approach where you can have specific aspects and global aspects.
    I have the equivalent question to this as to Fowler's claim that the Command pattern with one class per command is good for adding common behavior. Why use pre- and post-methods instead of just adding the code at the beginning or end of the exec method? Can you give me an example, not just of how it works, but of how it's useful?
    Dagfinn Reiersøl
    PHP in Action / Blog / Twitter
    "Making the impossible possible, the possible easy,
    and the easy elegant"
    -- Moshe Feldenkrais

  16. #16
    SitePoint Zealot prefab's Avatar
    Join Date
    Jan 2003
    Location
    Belgium
    Posts
    133
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by dagfinn
    I have the equivalent question to this as to Fowler's claim that the Command pattern with one class per command is good for adding common behavior. Why use pre- and post-methods instead of just adding the code at the beginning or end of the exec method? Can you give me an example, not just of how it works, but of how it's useful?
    Of course you would add the code within the execMethod if it were unique to that particular action. If it's an action that has a certain behaviour in common with (all) the other actions of that state, the (global) preExec and postExec methods are the right place to put it. Especially if you are defining a base class, it's logical to put it there, since the subclass shouldn't have to call it explicitly IMHO. If you're familiar with Ismo's _exposeDefaultVariables(), it's similar, in the sense that it's used to clearly setup the state-wide behaviour.

    You could setup some other objects in preExec; a template engine and some global template variables for example. Another use is to setup a page caching mechanism, where preExec would check for a cached version. If there's a cached version, the action wouldn't get executed, but the cache would be served. If not, preExec starts the buffer, the action is executed, while postExec saves the buffer to disk. (note that you could alternatively use preShow/postShow if the task needs it). Remember that you're not forced to use it, you can do and use whatever you like, since Ismo doesn't prescribe anything. In fact, it's our philosophy.

    There are two types of preExec/postExec methods, global ones, and specific ones. The specific preExec<action> and postExec<action> methods are especially usefull if you have simillarly named actions throughout the states. The usefullness becomes apparent when you apply (global) aspects to states. The state is completely unaware of the aspect, while the aspect let's you perform 3 basic techniques: preprocessing (preExec/preShow), postprocessing (postExec/postShow) and overriding the method entirely (you can also add actions/methods at will). You can imagine that this is quite powerfull. So to implement the examples above one could just create an aspect for that behaviour (you can apply multiple. ordered, global state aspects) and let the Application handle it (currently, the Application interacts with a factory class that will supply aspects if defined). This is not taken from thin air, as it's currently implemented (as a draft) and working wonderfully.

    - prefab

  17. #17
    SitePoint Guru
    Join Date
    Oct 2001
    Posts
    656
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    It seems to me that the Command Pattern would appeal more to the OO purist and this method would appeal more to the procedural programmer.
    Fully agreed here, but that is because the Command pattern is more object oriented. But forget about Struts, it's for Java and following it's principles blindly leads to IMHO frameworks that don't work very well for PHP *caugh*.. Phrame.. *caugh*

    The Ismo State class is just asking to be decomposed into several smaller classes. From the last paragraph of the previous post, I have assumed that it is possible for an Ismo_State subclass to look something like the below code. I admit that it might be a worst case scenario, but you have to admit that from your own description it is made possible, right?
    PHP Code:
    class Ismo_State
    {
        function 
    preExec_add() { .. .}
        function 
    preExec_edit() { ... }
        function 
    preExec_delete() { ... }
        function 
    preExec_list() { ... }}
        
        function 
    preShow_add() { ... }
        function 
    preShow_edit() { ... }
        function 
    preShow_delete() { ... }
        function 
    preShow_list() { ... }
        
        function 
    exec_add() { ... }
        function 
    exec_edit() { ... }
        function 
    exec_delete() { ... }
        function 
    exec_list() { ... }    
        
        function 
    postExec_add() { .. .}
        function 
    postExec_edit() { ... }
        function 
    postExec_delete() { ... }
        function 
    postExec_list() { ... }}
        
        function 
    postShow_add() { ... }
        function 
    postShow_edit() { ... }
        function 
    postShow_delete() { ... }
        function 
    postShow_list() { ... }

    That is one class with over 20 methods that all do something else! Now you try to convince me that this is not a bloated class and that it does "only one thing and is good at that one thing" according to OOP filosophy.

    The Ismo_State class is literally asking to be split into several classes! Instead of one State class with over 20 methods, what about 4 Action classes with only 5 methods each?
    PHP Code:
    class Ismo_Action
    {
        function 
    preExec() { ... }
        function 
    preShow() { ... }
        function 
    exec() { ... }
        function 
    postExec() { ... }
        function 
    postShow() { ... }

    This is the way the Ismo_State class would be done in OOP, period.

    I'll even try it from another perspective, that of object oriented analysis. That is the process of identifying the objects that make up a system.From your own wiki:
    A state is a logical grouping of actions. And an action is one function invoked by the application user. For example, an action can be add, preview or update and these kinds of actions could maybe belong to a forum posting state.
    What are the objects you can identify from this text? State, Action and Application User. Application User is not relevant here, so what remains are State and Action. So why do you completely forget about the Action object and put all of it into a State object? Exactly, because it is such an easy step to make from procedural coding.

  18. #18
    SitePoint Guru dagfinn's Avatar
    Join Date
    Jan 2004
    Location
    Oslo, Norway
    Posts
    894
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Captain Proton
    The Ismo_State class is literally asking to be split into several classes! Instead of one State class with over 20 methods, what about 4 Action classes with only 5 methods each?
    I agree with you that the Ismo_State class looks bloated, but I think that's a different discussion than the Command vs. Command Group discussion. That is, whether you have one command per class, or several. The Command Group pattern (it's a pattern if it's been used three times, and this one apparently has) doesn't require a bloated superclass. My implementation of it has no superclass at all. It might require a superclass at some later time, but so far I haven't seen a need for it.
    Dagfinn Reiersøl
    PHP in Action / Blog / Twitter
    "Making the impossible possible, the possible easy,
    and the easy elegant"
    -- Moshe Feldenkrais

  19. #19
    SitePoint Guru
    Join Date
    May 2003
    Location
    virginia
    Posts
    988
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I can see how that would get a little overly complex for one class yes. What do you think, if (for example) the command class held only the execute methods. Those methods return a view name (string) and then the controller (framework) would then get the view class needed according, and call the appropriate showMethod()? The view class would be completely separate.

    Matt

  20. #20
    SitePoint Member tyrak's Avatar
    Join Date
    Jan 2004
    Location
    Middle Finland
    Posts
    2
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Captain Proton
    That is one class with over 20 methods that all do something else! Now you try to convince me that this is not a bloated class and that it does "only one thing and is good at that one thing" according to OOP filosophy.
    I disagree, the Ismo_State class can be made bloated, however, if used correctly that will not be the case.

    You show a class having 20 methods, and even though that is possible, it is indeed something to be frowned upon. The intended usage is more along the lines of:

    PHP Code:
    class BaseState extends Ismo_Core_State_HTTP
    {
        
    // base state for the application
    }

    class 
    CachingState extends BaseState
    {
        function 
    preExec()
        {
            
    // cache if not cached otherwise show cached version
        
    }

        function 
    postShow()
        {
            
    // save output in cache
        
    }
    }

    class 
    ShowLatestPostsState extends CachingState
    {
        function 
    execDefault()
        {
            return 
    $this->execShow();
        }

        function 
    execShow()
        {
            
    // retrieve and show the latest posts
        
    }

    However, if one still wants to have each action in an own class it is possible to get that kind of behaviour by overriding the Ismo_Core_State_HTTP::execute() method in for example a BaseState class. This might seem like an overly complex way to get Ismo to work in your desired way, but as I tend to prefer having multiple action methods in one state class adding better support for action classes is not one of my priorities. Patches for this is gladly accepted


    To support show/view classes one has to currently override the Ismo_Core_State_HTTP::_showMethodMissing() method as prefab described in an earlier post. Patches to better to support this would also most certainly be applied.


    Captain Proton, I agree with you that using action classes is better OOP. But in my opinion using action methods in the state classes is a reasonable compromise. It gets the job done in an easy and efficient manner. Yes, it's procedural, but so what? I've been using OOP for six years now and I've come to understand that OOP is not always the best solution.

    I hope that in the future the Ismo framework will have the same amount of built-in support for both alternatives and a developer using Ismo can then freely choose which alternative to use, or use both! For example go with the action methods approach for states having just a few simple actions, and use action classes for the states with many complicated actions.

  21. #21
    SitePoint Guru
    Join Date
    Oct 2001
    Posts
    656
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Ok, then let's settle the argument by saying that we're both following different philosophy's in our frameworks

  22. #22
    SitePoint Guru dagfinn's Avatar
    Join Date
    Jan 2004
    Location
    Oslo, Norway
    Posts
    894
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by tyrak
    Captain Proton, I agree with you that using action classes is better OOP. But in my opinion using action methods in the state classes is a reasonable compromise. It gets the job done in an easy and efficient manner. Yes, it's procedural, but so what? I've been using OOP for six years now and I've come to understand that OOP is not always the best solution.
    I might add that Fowler's Table Data Gateway pattern from PoEAA is similarly procedural.
    Dagfinn Reiersøl
    PHP in Action / Blog / Twitter
    "Making the impossible possible, the possible easy,
    and the easy elegant"
    -- Moshe Feldenkrais

  23. #23
    simple tester McGruff's Avatar
    Join Date
    Sep 2003
    Location
    Glasgow
    Posts
    1,690
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by dagfinn
    You see, I believe that when I start out with the quasi-OO class and refactor to remove duplication, I'll end up with a simpler design that if I add complexity to begin with by making all those classes.
    Here's an interesting link about that: http://www.refactoring.be/thumbnails/cycle/cycle.html.

  24. #24
    SitePoint Wizard silver trophy kyberfabrikken's Avatar
    Join Date
    Jun 2004
    Location
    Copenhagen, Denmark
    Posts
    6,157
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    doing some sitepoint archeology here, are we ?

    what did dagfinn btw mean by
    Table Data Gateway pattern from PoEAA is similarly procedural
    it is obvious that querying a RDB has to be procedural at some point, or ?

  25. #25
    SitePoint Enthusiast
    Join Date
    Jul 2004
    Location
    Finland
    Posts
    73
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    All ideas seems to be taken already. I have made almost similar "Action group" system (I was inspired by Delphis Action system. Never heard about Ismo before.), and I've been quite happy how it works in practice. But it's still under developemen.

    Here's a little example.

    PHP Code:
    class Controller_formviewer extends JMVC_ActionController{

    //initialize variables, register action and instantiate class Objects here
        
    function initialize(){
            
    session_start();
            
    $this->model = new Model_formviewer(new adminDbConnection());
            
    $this->view = new View_formviewer($this->model);
            
    //1. parameter is name of the action, 2. is request method, and 3. is array of parameters that are passed to action.
            
    $this->registerAction('show_form','GET',array('form_name'=>false));
            
    $this->registerAction('save_content','GET');
        }
            
        
    //Main method is called after all requested actions are executed.  
        
    function main($action,$req,$res){
        }
        
        function 
    action_show_form($req){
            
    $formAction $_SERVER['PHP_SELF'].'?module='.$req->getAttribute('module').'&action=process_form';
            
    $this->model->loadForm($req->getAttribute('form_name'),$formAction);
            
    $this->view->display($req);
        }
        
        function 
    action_save content($req){
            if (!
    $this->model->getForm()) throw new UserException('Choose a form!');
            
    $saved $this->model->saveFormContent();
            
    $req->setAttribute('form_name',$this->model->getForm()->getName()); //set form_name attribute neened by show_form action. 
            
    $this->action_show_form($req); //You can call show_form action from here, so you don't need action chains.
            
    $saved && $this->model->setForm(false); //Destroy form after it's content is saved.
        
    }

    This code is from dynamic form building system that i'm workin on (uses PEAR quickForm). But I think it should show the idea clearly enough.

    I dont't think that classes are going to be too bloated if you desing your application well enough and do only necessary things in action methods. But one disadvantage is that you cannot reuse actions, though I don't see it as a very bad thing.


Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •