SitePoint Sponsor

User Tag List

Page 3 of 4 FirstFirst 1234 LastLast
Results 51 to 75 of 82
  1. #51
    ********* Victim lastcraft's Avatar
    Join Date
    Apr 2003
    Location
    London
    Posts
    2,423
    Mentioned
    2 Post(s)
    Tagged
    0 Thread(s)
    Hi...

    Quote Originally Posted by Hartmann
    The reason that I am wanting to use OOP is to make the shopping cart as modular and reusable as possible.
    The advantage of OO is that it will be easier to change. The disadvantage is that there will be a lot of design options initially and design is hard. The trick is to spread the design process over the lifetime of the project so that you make design decisions at a time of maximum information.

    Put more simply, start with the simplest possible cart, with no expansion possibilities in mind, and then refactor. It is actually easier to change the design as you go than you might think, as long as you keep things clean and minimal as you go. Adding an option or possibility is known as adding a flex point. It's a lot easier adding these one at a time with working code.

    Also don't start by putting methods into classes. Start with a single use case and code just enough for that example. If you have an example use case I can show you what I mean.

    yours, Marcus
    Marcus Baker
    Testing: SimpleTest, Cgreen, Fakemail
    Other: Phemto dependency injector
    Books: PHP in Action, 97 things

  2. #52
    SitePoint Wizard
    Join Date
    Aug 2004
    Location
    California
    Posts
    1,672
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I agree with lastcraft to start simple. The trick is to build a simple system that is open to growth from the beginning. And possibly only experience can guide you with that.

    A thing about using OO at a high level in web applications like a shopping cart is that the parts are so disparate that there is very little reuse except for some basic building blocks. I create things like a Cart class, an Order class, etc. anyway, but that is only for basic encapsulation. Starting with a huge class heirarchy often causes pain down the road.

    Restating what lastcraft said, start by implementing the basic features as small pieces of code that do a single thing. If something starts to get too big, stop and code the parts as standalone pieces. Then observe the direction the code is starting to take and rewrite cleaner code. Keep looking for places where the code does similar things at the algorithm level. These are opportunities to combine code, reducing the amount of code you will have to maintain.

  3. #53
    chown linux:users\ /world Hartmann's Avatar
    Join Date
    Aug 2000
    Location
    Houston, TX, USA
    Posts
    6,455
    Mentioned
    11 Post(s)
    Tagged
    0 Thread(s)
    Thanks for the suggestions.

    Marcus, I had the exact same thought, that I would plan extremely simple and code that and expand later on. We have a lot of planning time allowed for this project so I guess my first steps should be a lot of class layout.

  4. #54
    ********* Victim lastcraft's Avatar
    Join Date
    Apr 2003
    Location
    London
    Posts
    2,423
    Mentioned
    2 Post(s)
    Tagged
    0 Thread(s)
    Hi...

    Quote Originally Posted by Hartmann
    ...so I guess my first steps should be a lot of class layout.
    I wouldn't even go that fast. This is a developer's API right? It's a safe bet you will need a Cart class so that's the only decision I would start with...
    PHP Code:
    class Cart { } 
    We want it to start empty...
    PHP Code:
    class Cart {
        function 
    getItems() {
            return array();
        }

    Don't knock it, this is working code .

    Next we would like to add line items...
    PHP Code:
    class Cart {
        var 
    $_items;

        function 
    Cart() {
            
    $this->_items = array();
        }

        function 
    getItems() {
            return 
    $this->_items();
        }

        function 
    addItem($item) {
            
    $this->_items[] = $item;
        }

    I am carefully not using any references here because an important requirement of a cart is that it can be safely serialised. Note that we don't supply any persistence mechanism in the Cart. An important factor in keeping things minimal is to fight tooth and nail taking on any more responsibility than we need to. Otherwise not only have we inflicted an up-front design decision on ourselves, but we've inflicted one on our users as well.

    Now things are getting interesting because we would like to avoid duplicate rows. This means we want a way of getting a unique product ID and the ability to add quantities...
    PHP Code:
    class Cart {
        var 
    $_items;

        function 
    Cart() {
            
    $this->_items = array();
        }

        function 
    getItems() {
            return 
    $this->_items();
        }

        function 
    addItem($item) {
            for (
    $i 0$i count($this->_items); $i++) {
                if (
    $this->_items[$i]->getProduct() == $item->getProduct()) {
                    
    $this->_items[$i] = $this->_items[$i]->add($item);
                    return;
                }
            }
            
    $this->_items[] = $item;
        }

    Note that we let the items add themselves. If we were to poke around and ask for quantities we would have to know to construct a new item and any strange adding rules. We are a cart and our role is to survive the supermarket process, not to go about adding up totals or creating objects. That's the job of the checkout. Note that by being class name blind (no construction) the developers can add their own line item classes as long as they have a getProduct() and an add() method and they are serialisable. We have gained flexibility as a side effect of not doing any more than we have to.

    I can't see much more I'd want to add to a shopping cart, so let's go to the Item...
    PHP Code:
    class Item {
        function 
    getProduct() { }
        function 
    add($item) { }

    That's the absolute minimum I need right now for the cart. Assuming we want to start people off with a minimal version of this class that they can extend...
    PHP Code:
    class Item {
        var 
    $_product;

        function 
    Item($product$quantity) {
            
    $this->_product $product;
            
    $this->_quantity $quantity;
        }

        function 
    getProduct() {
            return 
    $this->_product;
        }

        function 
    getQuantity() {
            return 
    $this->_quantity;
        }

        function 
    add($item) {
            return new 
    Item($this->_product$this->_quantity $item->getQuantity());
        }

    Obviously the Item knows how to construct an Item, so we are giving nothing away here.

    Time to add another requirement. We would like the Cart to be able to display the current value of the purchase. This means a getBalance() on the Cart. Do we have to place all of that code into the Cart? No way. We will have a special BalanceCalculator...
    PHP Code:
    class BalanceCalculator {
        function 
    getBalance($items) { }

    We don't want every script in the application knowing about both Cart and BalanceCalculator. If we swap our calculator we would have to change every script, so to avoid that will mean hiding it inside the Cart. If we do this in the constructor then only the initial page of the sales process is affected...
    PHP Code:
    class Cart {
        var 
    $_items;
        var 
    $_calculator;

        function 
    Cart($calculator) {
            
    $this->_items = array();
            
    $this->_calculator $calculator;
        }

        function 
    getItems() {
            return 
    $this->_items();
        }

        function 
    addItem($item) {
            for (
    $i 0$i count($this->_items); $i++) {
                if (
    $this->_items[$i]->getProduct() == $item->getProduct()) {
                    
    $this->_items[$i] = $this->_items[$i]->add($item);
                    return;
                }
            }
            
    $this->_items[] = $item;
        }

        function 
    getBalance() {
            return 
    $this->_calculator->getBalance($this->_items);
        }

    Again I have added the absolute minimum code to get the job done. It's a bit like the devil's lawyer trying to weasle out of a contract for a soul. By not knowing about the BalanceCalculator we haven't prejudged the design. In so doing developers are free to add any type of balance calculation they like, including discounting and shipping costed versions. Also we haven't said what getBalance() returns. Probably a Money object, but in what currency? The Cart doesn't care.

    The Cart here is a mechanical object - there are no real business rules. Those rules would be placed in various policy classes like the BalanceCalculator. I think this is what arborint meant by separating data from code, although it's really separating rules from roles. It's a bit like your accountant working out your tax return. He gets the rules from the Inland Revenue. As a result you don't have to change your accountant every time a new tax regulation is introduced.

    Anyway, keep it minimal and introduce code only as you need it. Make every class have just one job to do and have it clever, but ignorant. Reuse will take care of itself.

    yours, Marcus
    Marcus Baker
    Testing: SimpleTest, Cgreen, Fakemail
    Other: Phemto dependency injector
    Books: PHP in Action, 97 things

  5. #55
    chown linux:users\ /world Hartmann's Avatar
    Join Date
    Aug 2000
    Location
    Houston, TX, USA
    Posts
    6,455
    Mentioned
    11 Post(s)
    Tagged
    0 Thread(s)
    Marcus,

    Thank you for a wonderful post. I am still trying to decide if I want to use classes to design this system or if I just want to program it with less structure using procedural code. To me an OO system makes more sense but it seems that it may take more time to complete because of more design planning.

  6. #56
    ********* Victim lastcraft's Avatar
    Join Date
    Apr 2003
    Location
    London
    Posts
    2,423
    Mentioned
    2 Post(s)
    Tagged
    0 Thread(s)
    Hi...

    Quote Originally Posted by Hartmann
    To me an OO system makes more sense but it seems that it may take more time to complete because of more design planning.
    The design side should be easier pound for pound because OO pieces are easier to slide into place when things go wrong. The extra design will come from the extra flexibility required and the softer requirements of designing for a community rather than just yourself. In fact coding for internal use and external use I would expect to differ by a factor of three.

    The fly in the ointment is whether the OO skills are present in your organisation. The learning curve is steep and it will definitely cause a slowdown. How important is time to market for this product?

    yours, Marcus
    Marcus Baker
    Testing: SimpleTest, Cgreen, Fakemail
    Other: Phemto dependency injector
    Books: PHP in Action, 97 things

  7. #57
    Non-Member
    Join Date
    Oct 2004
    Location
    downtown
    Posts
    145
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    To me an OO system makes more sense but it seems that it may take more time to complete because of more design planning.
    This is an old, old post though it's something I keep going back to over and over again as there is just too much in the thread to take in on one go,

    http://www.sitepoint.com/forums/showthread.php?t=36443

    I think I got the url right, have a look and see if it helps

  8. #58
    SitePoint Wizard
    Join Date
    Aug 2004
    Location
    California
    Posts
    1,672
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I would say that a shopping cart is a good example of where lastcraft and I disagree about how much OO to implement. The part of the cart he describes is a classic OO example but unfortunately it is about 2% of the problem and just too thin a layer to go object crazy. I use objects for the major pieces and associative arrays for much of the internal stuff. I find them much more flexible to add database fields or item qualities and not have to add code to the core objects but can ignore it until where it is needed, such as checkout, wish list, shipping calc or a product page.

    You can build it all OO (and I have) but I prefer simpler. If you love the OO style I can see how that way would work for you.

  9. #59
    SitePoint Wizard DougBTX's Avatar
    Join Date
    Nov 2001
    Location
    Bath, UK
    Posts
    2,498
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by lastcraft
    PHP Code:
    class Cart {
        var 
    $_calculator;
    ...
        function 
    Cart($calculator) {
    ...
            
    $this->_calculator $calculator;
        }
    ...
        function 
    getBalance() {
            return 
    $this->_calculator->getBalance($this->_items);
        }

    If you sent the Cart to the Calculator instead of calling getBalance, you could keep the Cart simpler. In your case, all the calculator is doing is getting $this->_items, which you can already do with getItems().

    The Cart is just a collection class, with a little bit of logic to deal with duplcates, so for me it would be finished here:

    PHP Code:
    class Cart {
        protected 
    $_items;

        function 
    __construct() {
            
    $this->_items = array();
        }

        function 
    getItems() {
            return 
    $this->_items;
        }

        function 
    addItem($newItem) { 
            foreach (
    $this->_items as $item) { 
                if (
    $item->sameProduct($newItem)) { 
                    
    $item->add($newItem); 
                    return;
                }
            }
            
    $this->_items[] = $newItem
        }

    As you can see, I've made items a little more automatous: an item knows wheher it is the same product as another item, the cart itself does not care, and an item knows how to add anoter item to itself. I've used a foreach instead of a for just to tidy it up a little.

    Here is my Item class:

    PHP Code:
    class Item 
        protected 
    $_product;
        protected 
    $_quantity;
        protected 
    $_unitCost;

        function 
    __construct($product$quantity$unitCost) { 
            
    $this->_product $product
            
    $this->_quantity $quantity
            
    $this->_unitCost $unitCost;
        }

        function 
    getProduct() { 
            return 
    $this->_product
        }

        function 
    getQuantity() { 
            return 
    $this->_quantity
        }
        
        function 
    getUnitCost() {
            return 
    $this->_unitCost;
        }
        
        function 
    getCost() {
            return 
    $this->_unitCost $this->_quantity;
        }
        
        function 
    sameProduct($item) {
            return (
    $this->_product  == $item->getProduct()) &&
                   (
    $this->_unitCost == $item->getUnitCost());
        }
        
        function 
    add($item) { 
            
    $this->_quantity += $item->getQuantity(); 
        }

    Marcus: what is the advantage of returning a new item with Quantity set, rather than just increasing the quantity of the item we have already? What are the advantages of doing it that way? Is it a case of trying to stop the item changing state once it is created?

    Lastly, here is the balance class and a BalanceView to demonstrate how I would access the cart. This code would be similar to the checkout, except the checkout would send the data to the database instead (or have the data sent to the database).

    PHP Code:
    class Balance {

        protected 
    $_cart;

        function 
    __construct($cart) {
            
    $this->_cart $cart;
        }

        function 
    getTotal() {
            
    $total 0;
            foreach (
    $this->_cart->getItems() as $item) { 
                
    $total += $item->getCost();
            }
            return 
    $total;
        }

    }

    class 
    BalanceSheetView extends Balance {
        
        function 
    getHTML() {
            
    $s  '<table><tr><th>product</th><th>quantity</th><th>cost</th></tr>';
            foreach (
    $this->_cart->getItems() as $item) { 
                
    $s .= '<tr><td>'.$item->getProduct().'</td>';
                
    $s .=     '<td>'.$item->getQuantity().'</td>';
                
    $s .=     '<td>'.$item->getCost().'</td></tr>';
            }
            
    $s .= '<tr><th colspan="2" style="text-align: right">total cost:</th>';
            
    $s .= '<td>'.$this->getTotal().'</td></tr>';
            
    $s .= '</table>';
            return 
    $s;
        }    

    And for those still with me, here is my code to make the classes play together. All it does it create a cart, add some items to it, and then create a Shset with the contents of the Cart. In real life, these addItems would be called from user requests, rather than just side by side as they are here. The Cart would be stored in the session or the database for the user to come back to later.

    PHP Code:
    $Cart = new Cart;
    $Cart->addItem(new Item('Window'31));
    $Cart->addItem(new Item('Window'210));
    $Cart->addItem(new Item('Window'610));
    $Cart->addItem(new Item('Door',   1100));
    $Cart->addItem(new Item('Wall',   4100));

    $Sheet = new BalanceSheetView($Cart);
    echo 
    $Sheet->getHTML(); 
    Regards,
    Douglas
    Hello World

  10. #60
    SitePoint Wizard DougBTX's Avatar
    Join Date
    Nov 2001
    Location
    Bath, UK
    Posts
    2,498
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    With just these changes below, Collection (basically Cart from the example above) now supports recursion - just send addItem items which inherit from Collection. Walk will walk all over them.

    PHP Code:
    class Collection {
    ...
        function 
    addItem($newItem) { 
            return 
    $this->_items[] = $newItem
        }
        
        function 
    walk($walker) {
            
    $walker->walk($this$this->_items);
        }

    }

    class 
    Walker {

        function 
    walk($item$children) {
            echo 
    $item->toString();
            foreach (
    $children as $child) {
                
    $child->walk($this);
            }
        }
        

    A small modification to the Collection class (the Cart inherits from this) to make it return a reference to the last Item added, and a Walk function. The Walk function isn't strictly needed, though I think it makes the code clearer. It gives the Collection some control over which items are walked over, though in this case the walk function could just look like this:

    PHP Code:
    class Walker 

        function 
    walk($item) { 
            echo 
    $item->toString(); 
            foreach (
    $item->getItems() as $child) { 
                
    $this->walk($child);
            } 
        } 
         

    Note that it is the Walker which does the recursion, all the Collection (Cart) does is send out information which is requested by the walker. This means that you can do anything with the data from the tree, particularly if you don't use the Collection::walk shortcut.

    Using the walk function on the Collection classes (and their Node descendants) can be called like this:

    PHP Code:
    $walker = new Walker;
    $root->walk($walker);

    // or without the Collection::walk shortcut:
    $walker = new Walker;
    $walker->walk($root); 
    Very nice, though a little off topic. How would this be handled in a procedural world?

    Douglas
    Hello World

  11. #61
    ********* Victim lastcraft's Avatar
    Join Date
    Apr 2003
    Location
    London
    Posts
    2,423
    Mentioned
    2 Post(s)
    Tagged
    0 Thread(s)
    Hi...

    Quote Originally Posted by DougBTX
    The Cart is just a collection class, with a little bit of logic to deal with duplcates, so for me it would be finished here:
    Agree totally. Hey, I wrote it as fast as I could type . Hm, which is not that fast actually. It was really only an illustration of the thought processes behind design and the method of dribbling in requirements one by one.

    Quote Originally Posted by DougBTX
    Marcus: what is the advantage of returning a new item with Quantity set, rather than just increasing the quantity of the item we have already? What are the advantages of doing it that way? Is it a case of trying to stop the item changing state once it is created?
    Yes, that's exactly it. Gets rid of setters and things as well and stops you accidently having references. That's important in this context because of the serialisation requirement.

    yours, Marcus
    Marcus Baker
    Testing: SimpleTest, Cgreen, Fakemail
    Other: Phemto dependency injector
    Books: PHP in Action, 97 things

  12. #62
    SitePoint Wizard
    Join Date
    Aug 2004
    Location
    California
    Posts
    1,672
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    with a little bit of logic deal with duplcates
    what is the advantage of returning a new item with Quantity set, rather than just increasing the quantity of the item we have already
    Gets rid of setters and things as well and stops you accidently having references
    Unfortunately real carts do not have the luxury of generalization. Some products when added increment the quantity, others add a seperate item to the cart because the have some quality (like color) that makes each item of the same SKU a different thing for the user to deal with. So the cart needs to know about products. And that's the tip if the iceberg of the complexity. Keep going ... I want you to get to something I can use.

  13. #63
    ********* Victim lastcraft's Avatar
    Join Date
    Apr 2003
    Location
    London
    Posts
    2,423
    Mentioned
    2 Post(s)
    Tagged
    0 Thread(s)
    Hi...

    Quote Originally Posted by arborint
    Unfortunately real carts do not have the luxury of generalization.
    That'll be why this version is just a starting point .

    Quote Originally Posted by arborint
    Some products when added increment the quantity, others add a seperate item to the cart because the have some quality (like color) that makes each item of the same SKU a different thing for the user to deal with.
    The usual convention is to treat a different colour as a completely different product code, for example the EPOS system does this. The same for different sized packages. You need to stick with this system in order to interface with back end systems.

    A more "interesting" problem is the one of special offers, such as a free bag of crisps with every two boxes of biscuits. One solution is to have a separate product in the catalog, but this complicates the display. How do you display three boxes of biscuits for example (two items)? What if they remove one of the boxes only that was in the a pair? That would cause a change of product code that the Cart doesn't deal with.

    Splitting them up is more natural, but fiddly. By making the crisps a bonus item with a special price you introduce the need for some kind of trigger when the boxes are removed. If we use an observer then we introduce references, but it means that everything can happen within the items. The downside is that unserialising is more complicated and can cause dependencies on the items. You also end up with an empty item when the crisps dissappear. It's all just untidy.

    My own favourite (from one attempt) is to have all of the boxes as a single decorated item, say OfferItem as the decorator, which adds the crisps. You can create different types of OfferItem, but I get smoother (YMMV) code if I plug into it an OfferPolicy object (say BuyXGetYFree) and have just one OfferItem container class. That way developers can add their own special offer classes without having to rewrite all of the mechanics. Likely they already have something within their catalog system already.

    Quote Originally Posted by arborint
    So the cart needs to know about products.
    Nope.

    Quote Originally Posted by arborint
    And that's the tip if the iceberg of the complexity. Keep going ... I want you to get to something I can use.
    Well, we are a little short on real requirements right now.

    yours, Marcus
    Marcus Baker
    Testing: SimpleTest, Cgreen, Fakemail
    Other: Phemto dependency injector
    Books: PHP in Action, 97 things

  14. #64
    chown linux:users\ /world Hartmann's Avatar
    Join Date
    Aug 2000
    Location
    Houston, TX, USA
    Posts
    6,455
    Mentioned
    11 Post(s)
    Tagged
    0 Thread(s)
    So you all want some more in-depth feature requirements so that we can build a more functional model/prototype?

  15. #65
    SitePoint Wizard
    Join Date
    Aug 2004
    Location
    California
    Posts
    1,672
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    The usual convention is to treat a different colour as a completely different product code, for example the EPOS system does this. The same for different sized packages. You need to stick with this system in order to interface with back end systems.
    Clients love to hear that.
    It's all just untidy.
    I agree and though you could probably haute engineer an all pattens based OO cart (I've come close on simpler ones), in my experience it is just a bunch of simple problems and you greatly reduce your design and coding time when you code much of the internals procedurally.

  16. #66
    SitePoint Wizard DougBTX's Avatar
    Join Date
    Nov 2001
    Location
    Bath, UK
    Posts
    2,498
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by arborint
    Clients love to hear that.
    Just do it like my example above: get objects to compare themselves with eachother. Leave that code out of the cart. If one item wants to say "are you the same colour as me?" then all it has to do is check if it is the same product (compare interfaces) and then check the colour.

    I don't know what you mean by an "all pattens based OO cart". You don't base thing on patterns, the patterns are a product of the code. If you read the code and you see a documented pattern emerging, then you can use the documentation to reinforce the pattern. It does not work nearly as well the other way around - you'll end up applying other people's solutions to your code to fix problems in their code, not yours. That seems to be the situation where you fall back to procedural. You've got to remember that patterns won't write your application for you - you are still the programmer.

    All this seems to be implying that patterns only exist in OO code: that is BS. Patterns exist in procedural code too, they just don't get called patterns, or don't get given names. For example: the recursive function for reading multi level trees of data. The pattern exists in both procedural and OO code, the only difference is implementation details.

    Douglas
    Hello World

  17. #67
    SitePoint Zealot
    Join Date
    Oct 2004
    Location
    naperville
    Posts
    189
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by arborint
    Clients love to hear that.
    Do it internally. Combine a product ID with a 2 digit size code and a 2 digit color code to create a unique id - say, a large red stereo could be 5460103 where 546 is the product id, 01 is the size and 03 is the code. This way, each item variant will be unique without duplicate data.

  18. #68
    SitePoint Wizard
    Join Date
    Aug 2004
    Location
    California
    Posts
    1,672
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    My point about different items was not that you couldn't force them to be the same if you want to. My point was that different items behave very differently and something has to handle them in a ways that customers think about them. Some have color and size, some have only certain size and color combinations, some can only exist or change price or quantity/quality when with another product, or has a monogram, etc. there are honestly an infinite number of variations and exceptions. It is my experience that carts are an example of a programming problem that does not require inheritance, have much code reuse, or need many of the benefits that OO provides. I don't "fall back to procedural" (implying as you "OO Guys" do that it is inferior) but choose procedural because I find it is a better solution in this case.
    All this seems to be implying that patterns only exist in OO code: that is BS. Patterns exist in procedural code too, they just don't get called patterns, or don't get given names.
    I might agree that the concepts behind patterns exist in general., But let's face it, they started as OO design patterns but today they really are OO implementation patterns. It is a separate and interesting discussion of why "they just don't get called patterns, or don't get given names" or just don't get used in procedural programming.

  19. #69
    SitePoint Wizard DougBTX's Avatar
    Join Date
    Nov 2001
    Location
    Bath, UK
    Posts
    2,498
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I dissagree with you comment that "different items behave very differently". The list of examples you give shows that different items can record different information about the user's selection, but the behaviour is the same: each item records information about the user's selection.

    In any system, different objects have different roles. I think it was arborint who said that the Cart class examplewas only a "very thin" layer. It is a very thin layer: all it does is handle adding and removing items that the user selects to and from the cart. It doesn't handle calculating the cost of the purchace, it doesn't handle whether an item should be blue or red, it doesn't even handle telling the user what is in the cart. All these different thing belong in other places.

    For example, go into a shop and buy something in a two for one deal. When you pick up the second can of coke, its price tag doesn't suddenly disintegrate in your hand. All that is handled by the calculator inside the checkout. Quite often the process is as follows:

    I see one can of coke, add $1.00 to the receipt.
    I see one can of coke, add $1.00 to the receipt.
    Hay! I've got two cans of coke. Subtract $1.00 from the reciept.

    You reciept may look like this:

    Coke $1.00
    Coke $1.00
    Coke offer -$1.00

    Total: $1.00

    The user removes a can of coke from the cart. Doesn't change anything. The reciept looks like this:

    Coke $1.00

    Total: $1.00

    But let's face it, they started as OO design patterns but today they really are OO implementation patterns.
    If OO was just design patterns, I don't think that I would use it. Saying that OO is just a fixed set of patterns is like saying that procedural code is just if statments.
    Hello World

  20. #70
    ********* Victim lastcraft's Avatar
    Join Date
    Apr 2003
    Location
    London
    Posts
    2,423
    Mentioned
    2 Post(s)
    Tagged
    0 Thread(s)
    Hi...

    Quote Originally Posted by arborint
    My point was that different items behave very differently and something has to handle them in a ways that customers think about them. Some have color and size, some have only certain size and color combinations, some can only exist or change price or quantity/quality when with another product, or has a monogram, etc. there are honestly an infinite number of variations and exceptions.
    This is all the subject of the catalog and the underlying ordering system. You don't want to place that kind of detail into the cart or it will bloat like crazy. Once a product has been successfully earmarked from the catalog to the cart, the cart does not need to know these things. Otherwise you will never be able to treat the cart and catalog as separate components.

    Quote Originally Posted by arborint
    I don't "fall back to procedural" (implying as you "OO Guys" do that it is inferior) but choose procedural because I find it is a better solution in this case.
    As one of those OO guys I don't "imply" that procedural is more primitive. I flat out state it .

    @Haartmann: Yes please, give us another requirement (just one at a time though).

    yours, Marcus
    Marcus Baker
    Testing: SimpleTest, Cgreen, Fakemail
    Other: Phemto dependency injector
    Books: PHP in Action, 97 things

  21. #71
    Non-Member
    Join Date
    Oct 2004
    Location
    downtown
    Posts
    145
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    As one of those OO guys I don't "imply" that procedural is more primitive. I flat out state it


    Top one

  22. #72
    chown linux:users\ /world Hartmann's Avatar
    Join Date
    Aug 2000
    Location
    Houston, TX, USA
    Posts
    6,455
    Mentioned
    11 Post(s)
    Tagged
    0 Thread(s)
    Requirement 2;

    All customers can have one to many shipping addresses. They must be able to add/edit/delete addresses (and give them nicknames) or just fill in an address when they make the order.

    Oh, remember, I am having to do this in PHP4.3 so things like __construct() can't be used (right?).

    I know you said only one requirement at a time but I just thought of a big one... The cart needs to be as modular as possible so that it can fit into different interfaces easily.

  23. #73
    ********* Victim lastcraft's Avatar
    Join Date
    Apr 2003
    Location
    London
    Posts
    2,423
    Mentioned
    2 Post(s)
    Tagged
    0 Thread(s)
    Hi...

    Quote Originally Posted by Hartmann
    All customers can have one to many shipping addresses. They must be able to add/edit/delete addresses (and give them nicknames) or just fill in an address when they make the order.
    This is a different part of the system, and heading off into application rather than library territory, but here goes some sample code...
    PHP Code:
    $finder = &new PersonFinder();
    $person = &$finder->findPersonById($_SESSION['user_id']);
    $destination = &$person->getDestination($_GET['nickname']);

    $shipping = &new OurShippingCostCalculator();

    $checkout = &new Checkout($shipping);
    $cost $checkout->calculatePayment($destination$cart);

    // Once payment has been confirmed...

    $catalog = &new CatalogSession(...);

    $checkout = &new Checkout($shipping);
    $checkout->dispatch($cart$_SESSION['destination'], $catalog); 
    Is this reasonable or do you see some other interface to the application developer? Person and PersonFinder are nothing to do with us so I have left everything up to them other han supplying us with a destination.

    I have made a lot of assumptions here. I am assuming that we want to allow connection to any CMS or database that the developer chooses. I am assuming that the developer will control how the Destination class is stored. I am assuming that the Destination can also written by the developer, although we might supply a few simple ones such as a postal address.

    We would like to control only the interface of Destination, ShippingCostCalculator and CatalogSession for maximum flexibility. Checkout is all us.

    Here is the code that this example pretty much forces...
    PHP Code:
    class Destination { }   // Might just be a hash

    class ShippingCostCalculator() {
        function 
    getShippingCost($destination$items) { }
    }

    class 
    CatalogSession() {
        function 
    subtract($item) { }
        function 
    commit() { }
    }

    class 
    Checkout() {
        function 
    Checkout(&$shipping) { }
        function 
    calculatePayment($destination$cart) { }
        function 
    dispatch($cart$destination, &$catalog) { }

    CatalogSession is our transactional contact with the CMS and is a UnitOfWork pattern. Likely the cost calculator in the cart can be the same one that handles shipping, but I'll wait for more info.

    I don't want to code further without more detail as everything is a bit abstract right now. Do you have a specific CMS that you might want to add and subtract items from that I could use as a first example? What do the method calls look like in this case? Where does the request for the order go? Presumably items have to be subtracted from the catalog and some kind of message has to be sent to the warehouse people? Also a payment has to be made so enough information has to be produced from the checkout process to satisfy the next step in the chain. What is required in the simplest case?

    I just need one possible scenario for now. Its a lot easier to generalise from a concrete example. Beside, I'll end up designing my cart rather than you designing yours .

    Quote Originally Posted by Hartmann
    Oh, remember, I am having to do this in PHP4.3...
    Me too.

    Quote Originally Posted by Hartmann
    I know you said only one requirement at a time but I just thought of a big one... The cart needs to be as modular as possible so that it can fit into different interfaces easily.
    The more modular it becomes, the more complex and indirected the code becomes. This makes it harder to use and so nobody reuses it. As a library writer you have to balance breadth of audience against the learning curve. You really don't want any more flexibility than you really need once you have identified your user base. This is why we go one step at a time. We add features in order of likely need until we get close to overload. On each scneario we add just enough code to do the job and no more.

    If you want more flexibility, then add more scenarios, but do it one at a time.

    yours, Marcus
    Marcus Baker
    Testing: SimpleTest, Cgreen, Fakemail
    Other: Phemto dependency injector
    Books: PHP in Action, 97 things

  24. #74
    chown linux:users\ /world Hartmann's Avatar
    Join Date
    Aug 2000
    Location
    Houston, TX, USA
    Posts
    6,455
    Mentioned
    11 Post(s)
    Tagged
    0 Thread(s)
    Awesome lastcraft!

    I will try and keep it in the scenario realm. So we have a customer, we have a cart, we need to model the different aspects of what the customer can do. Such as billing. Do we handle that as an object? I mean, it really is a very small piece. Basically it covers all of the billing information per customer. I am guessing that this functionality could be done in the Customer class.

    What I am thinking next is maybe the items/products that need to be displayed. A product has an image, description, price, etc. tied to it so all of those things need to be displayed.

    The problem that I am having with all of this is putting it together with the interface/look that our designers give to me. How portable will this be to the next design they give me? I want to be able to "package" the system enough to where plugging it in to a site that has a different look and feel to it is not very hard.

  25. #75
    SitePoint Wizard
    Join Date
    Aug 2004
    Location
    California
    Posts
    1,672
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I think Hartmann's Requirement 2 was a little too far afield. Let's say Requirement 1 was get an item (all I would want added to the code above is to be able to get a quality). Then Requirement 2 should be add an item. Here is my cut at Requirement 2.

    1. When you add an product it should always add an item if that product is not currently in the cart.

    2. If that product is in an item in the cart then, depending on the product, it should either increase the quantity of the existing item or add another item with the same product.

    3. Also adding an item should allow specifying a quantity and any number of qualities.


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
  •