SitePoint Sponsor

User Tag List

Page 4 of 11 FirstFirst 12345678 ... LastLast
Results 76 to 100 of 274
  1. #76
    SitePoint Addict
    Join Date
    Oct 2004
    Location
    Sutton, Surrey
    Posts
    259
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by MickoZ
    The reason to have two classes (User and UserMapper) is to separate two different topic even thought they can be linked to one topic.
    I am working from the description of a mapper class given at the start of this thread by JNKlein:
    Quote Originally Posted by JNKlein
    Let me use the example of the User class, something I'm sure we're all familiar with. Suppose one of the properties of a "user" is "username". You whip up your User class, then you whip up a UserMapper class, which has a method insert(User). The internals of this method inevitably make specific reference to the properties of a User object AND inevitably make specific reference to your method of storing the data (even with a DAO you need to specifically state where you are putting the info... "INSERT ... WHERE username = etc).
    This appears to be saying that when I wish to perform a function on a User which does not involve database access then I use the User class, while if it DOES involve database access then I must use the UserMapper class. This is what I absolutely disagree with. By having more than one class available when I wish to perform a function on a User is breaking encapsulation. It also forces the calling script to know what kind of activity it requires so that it can call the right class. Because this information is required OUTSIDE the class it also breaks the principle of information hiding.

    Now, if it were arranged so that I only ever accessed the User class, and if the code within that class decided that some database access were required and it accessed the UserMapper class without me even being aware of it, then that would be a step in the right direction.

    But hang on a minute! isn't that what I already have in my design? Except that in my case I don't have a UserMapper class, I have a Data Access Object. Also I don't have a separate Mapper class for each entity, but I do have a single data access object for the entire application. Somehow my design seems more efficient.

  2. #77
    SitePoint Addict
    Join Date
    Oct 2004
    Location
    Sutton, Surrey
    Posts
    259
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by MickoZ
    If they are called pattern, it is either that they fit to fix some common problem (pattern to do something) or that people often do it that way (a pattern way). They might just inspirate us and it is nothing (and I doubt people do that 100%) to follow 100% to the letter. But if you take something like Singleton, it is useful, it is simple, it is a clean way to do it. You may or not have read about those DataMapper/ActiveRecord/Etc. However, they might also give you a clean way to do stuff. Some of the stuff are quite intuitive, some less. Blah blah.
    Patterns can be useful, I agree. But if you implement a pattern badly, or implement an inappropriate patern, then that can be much worse than not using a pattern at all.
    The worse thing that an aspiring programmer can do it pick a pattern because it looks 'cool' and try to implement it without having the original problem that the pattern is trying to solve. If you write code that works there is no point in changing it just so that it follows the pattern, because by changing it you may be introducing bugs or inefficiencies.
    You should be aware of patterns, but you need to know when a particular pattern can help solve a problem instead of introducing new ones. That takes skill and experience. A simple rule of thumb is this: Don't bother with a pattern unless you have a problem which that pattern is designed to solve.

  3. #78
    ********* 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 MickoZ
    Well my question is this: what you suggest as reference/roadmap if you can suggest that?
    This is a thread in itself (you should start it). Here is a stream of conciousness run of random advice I have found useful for myself and when consulting and mentoring...

    Write code. Lot's of it. Never waste an opportunity to express design in code form. Whenever I respond to Sitepoint posts for example I try to include code snippets. It's another chance to write stuff in an area I many never work in, and also others can critique it and suggest counter examples.

    The basic mechanics of OO you get just by doing. It's sufficient to to have a few classes in a sea of procedural code to start to aclimatise. Don't underestimate this process of sinking into a new paradigm. After all learning data modelling or logic programming is just as strange at first, but everybody expects to learn OO in one go. It sounds like you are already past this.

    Refactoring is the next step (the book by Martin Fowler is a must have). This is the technique that allows you to get things wrong so that you can then get them right. The power of OO is it's flexibility so why not leverage that every second you are writing code. By making and fixing lots of little mistakes in a short time frame you learn fast. The big impact of this book comes about three weeks after you read it (not all of it, just some will do). It clicks and you jump a level.

    Patterns are tricky. Gather as many of them as you can at all times then, once you are actually programming, forget them . A pattern is like a tool in a toolbox. You don't start making a chair by thinking how can I make a chair with a drill, you just start making the chair and the point when you need the drill you subconciously grab for it. After a while the core GOF patterns just start to meld together into a style of thinking.

    Do as much of this learning with other people as you can. If you can manage it, try pair programming. If you cannot, find ways of getting code reviews. They are a frequent feature of this forum. You won't get definitive answers (and only you will know what's best for you), but you'll get some eye openers. Try to do design in groups around a whiteboard. If you work alone then group design sessions will be your biggest loss. Join a user group or do anything you can to correct this.

    Enterprise patterns (Martin Fowler again and also Domain Driven Design by Eric Evans) are easier to grasp. Keep these catalog books around when you are working. It is only necessary to skim these books at first. You want a memory jogger when you come accross a related problem in your code.

    Always focus on the immediate problem and try to write the minimum amount of code to solve just that problem. Don't worry about reuse or other meta issues, you will just log jam your brain. Hack if necessary and then design it later by refactoring. Also look at minimal designs from the point of view of coding techniques. Feature driven design, CRC cards and Agile Modelling are all such techniques. Oh yeah, look up YAGNI.

    Have a look at unit testing and Test Driven Design (Kent Beck).

    OO allows redesign as you go. Leverage this against difficult problems by solving just one feature at a time. Get that working and then add another and refactor. Iterative development works well with OO and your project managers will be happier. Adding flex points (the ability to change the software at build or run time) is treated the same way. Scrum, RUP and XP are built around this.

    Have a look around the C2 wiki.

    Collect these books: Refactoring (Fowler), Design Patterns (Gamma, Helm, Johnson, Vlissides), Patterns of Enterprise Application Architecture (Fowler), Thinking in Java (Eckel, but I've not yet read it), Agile Software Development (Martin), Roles, Responsibilities and Collaborations (Wirfs-Brock), Domain Driven Design (Evans), The Pragmatic Programmer (Hunt, Thomas), Test Driven Development by Example (Beck).

    Sleep a lot.

    Talk to lot's of people.

    Have fun.

    Actually, if you just manage that last one, the others will follow .

    yours, Marcus
    Last edited by lastcraft; Nov 12, 2004 at 20:19. Reason: Forgot the Pragmatic Programmer
    Marcus Baker
    Testing: SimpleTest, Cgreen, Fakemail
    Other: Phemto dependency injector
    Books: PHP in Action, 97 things

  4. #79
    SitePoint Enthusiast MickoZ's Avatar
    Join Date
    Jul 2004
    Location
    Canada, Qc
    Posts
    42
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Thanks lastcraft, interesting ;-)

    I liked the Sleep alot.

    I also tried CRC card sometime ago... I liked it.

    Actually for working, I work daily in a place they use Java, but my project is not 100% object oriented (it is mostly SQL driven for now, but I might look to refactor a part of the code, I am sure it can be cleaner, it always can!). And beside my day job, I do some contract in PHP, my client wish to hire me full time at high price... maybe working too much sometime ;-) and that is kinda my first year working. I am usually pretty fast at learning stuff (at school, etc.) -- not to brag but to brag. I use to do my stuff in less time than most people (maybe the thinking). But of course when you get out of school, problems can get bigger. Also I sometime think I read too much, don't act enough (code code code ).

    I probably already thought of a lot of thing in OO, Pattern, etc. liked I said, but sometime seeing concret example of other, or the view of other (who spent 30-50 days -- I mean many days -- on a topic rather than 2-3 hours to explain it to us a simple way!) enlight us...

    But then sometime knowing too much also confuse you

    Note: Thinking in Java is free and you probably know this, I already readed some of it and tried to do the exercice (at beginning of the year). But if I remember well the chapter are LONG read... that is maybe the only drawback. I am not a native English reader/speaker/etc. so maybe I am more slow than most of you to understand well in English but I do the effort. I think I will reread fast that book one day to see, maybe I will never have [time] to reread it. ;-)

    I feel a bit tired, I will go lay in my bed

    Sleep for da weak. :-)

    Have fun -- in ANYTHING you do is a good thing.
    Some people think I go too far sometime when trying to achieve something (being perfectionnist), but I do not necessary invest that much more time than them, but it is fun for me to do thing "better", to achieve more, etc.

    The most complex thing is to make thing simple. ;-)

  5. #80
    SitePoint Addict
    Join Date
    May 2003
    Location
    Calgary, Alberta, Canada
    Posts
    275
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Tony Marston
    That is because I believe in the KISS principle. I do not like to make anything more complicated that it needs to be.
    Quote Originally Posted by Tony Marston
    I am not confusing the issue with subclasses. I am merely saying that I have a single User class, not a User and a UserMapper class.
    By "encapsulating" everything in a single "User" class you have completly distorted the DAO pattern.

    Here is your interface for a Person in your example application. This is not code writing by someone who believes in "Keeping it Simple Stupid" nor does it take into account massive amounts of Object Oriented Principles.

    There is some serious refactoring to do.

    PHP Code:
    class Person extends Default_Table {
        function 
    Person();
        function 
    getFieldSpec_original ();
        function 
    getValRep ($item 'star_sign');
        function 
    _cm_commonValidation ($fieldarray$orignaldata);
        function 
    _cm_getExtraData ($where$fieldarray);
        function 
    _cm_getForeignData ($fieldarray);
        function 
    _cm_getInitialData ($fieldarray);
        function 
    _cm_popupCall ($popupname, &$where);
        function 
    _cm_pre_getData ($where_str);
    }
    class 
    Default_Table {
        function 
    Default_Table ();
        function 
    deleteRecord ($fieldarray);
        function 
    deleteSelection ($selection);
        function 
    formatData ($fieldarray);
        function 
    getClassName ();
        function 
    getCount ($where);
        function 
    getData ($where) ;
        function 
    getData_unformatted ($where);
        function 
    getDBname () ;
        function 
    getEnum ($fieldname) ;
        function 
    getErrors () ;
        function 
    getExpanded ();
        function 
    getExtraData ($input) ;
        function 
    getFieldArray () ;
        function 
    getFieldSpec () ;
        function 
    getFieldSpec_original () ;
        function 
    getInitialData ($where) ;
        function 
    getLastPage () ;
        function 
    getLookupData () ;
        function 
    getMessages () ;
        function 
    getNavButtons ($task_id) ;
        function 
    getNodeData ($expanded$where=null);
        function 
    getNumRows () ;
        function 
    getOrderBy () ;
        function 
    getOrderBySeq () ;
        function 
    getPkeyArray ();
        function 
    getPkeyNames () ;
        function 
    getTableName () ;
        function 
    getValRep ($item$where=null) ;
        function 
    getWhere () ;
        function 
    insertMultiple ($fieldarray) ;
        function 
    insertRecord ($fieldarray) ;
        function 
    popupCall ($popupname$where$script_vars) ;
        function 
    popupReturn ($fieldarray$return_from$selection);
        function 
    setAction ($action) ;
        function 
    setDefaultOrderBy ($sql_orderby) ;
        function 
    setFieldAccess () ;
        function 
    setFieldArray ($fieldarray) ;
        function 
    setOrderBy ($sql_orderby) ;
        function 
    setOrderBySeq ($sql_orderby_seq) ;
        function 
    setPageNo ($pageno '1') ;
        function 
    setRowsPerPage ($rows_per_page) ;
        function 
    setSqlSearch ($sql_search) ;
        function 
    sqlAssemble ($where) ;
        function 
    updateLinkData ($fieldarray$postarray) ;
        function 
    updateMultiple ($fieldarray$postarray);
        function 
    updateRecord ($fieldarray) ;
        function 
    updateSelection ($replace$selection);
        function 
    validateDelete ($fieldarray) ;
        function 
    validateInsertArray ($fieldarray) ;
        function 
    validateUpdateArray ($fieldarray) ;
        function 
    _cm_commonValidation ($fieldarray$originaldata) ;
        function 
    _cm_deleteSelection ($selection) ;
        function 
    _cm_formatData ($fieldarray) ;
        function 
    _cm_getExtraData($where$fieldarray) ;
        function 
    _cm_getForeignData ($fieldarray) ;
        function 
    _cm_getInitialData ($fieldarray) ;
        function 
    _cm_popupCall ($popupname$where) ;
        function 
    _cm_popupReturn ($fieldarray$return_from$selection) ;
        function 
    _cm_post_deleteRecord ($fieldarray) ;
        function 
    _cm_post_getData ($rowdata, &$where) ;
        function 
    _cm_post_insertRecord ($fieldarray) ;
        function 
    _cm_post_updateMultiple ($fieldarray) ;
        function 
    _cm_post_updateRecord ($fieldarray$old_data) ;
        function 
    _cm_pre_deleteRecord ($fieldarray) ;
        function 
    _cm_pre_getData ($where_str) ;
        function 
    _cm_pre_insertRecord ($fieldarray) ;
        function 
    _cm_pre_updateLinkdata ($fieldarray, &$postarray) ;
        function 
    _cm_pre_updateMultiple ($fieldarray) ;
        function 
    _cm_pre_updateRecord ($fieldarray) ;
        function 
    _cm_updateSelection ($replace$selection);
        function 
    _cm_validateDelete ($fieldarray) ;
        function 
    _cm_validateInsert ($fieldarray) ;
        function 
    _cm_validateUpdate ($fieldarray$originaldata) ;
        function 
    _dml_deleteRecord ($fieldarray);
        function 
    _dml_deleteRelations ($fieldarray);
        function 
    _dml_getCount ($where);
        function 
    _dml_getData ($where);
        function 
    _dml_getEnum ($item);
        function 
    _dml_insertRecord ($fieldarray);
        function 
    _dml_ReadBeforeUpdate ($where);
        function 
    _dml_updateRecord ($fieldarray$oldarray);
        function 
    _dml_updateSelection ($selection$replace);
        function 
    _dml_validateDelete ($fieldarray);
        function 
    _getDBMSengine ();
        function 
    __sleep () ;

    Take a look at the common functions. Everything to do with meta data about an entity, put in some sort of TableMetaData object. Everthing to do with insert/update validation put in a Validation bject. Pass the validation object the TableMetaData object and the data to be validated. Everything to do with querying the database(setOrderBy(), setWhere() etc..) put in a query object and pass that object to the DAO.

    Having 100 or so functions in a class is a serious bad code smell. Doing these things and refactoring will drop the amount of code in your architecture by a ton.

    Quote Originally Posted by Tony Marston
    You are arguning just because I dare to disagree with you. Just because I choose to read from a diffent design 'bible' you seem to think I am a heretic. I do not have DataAccessor or DataMapper classes for the simple reason that I do not follow that particular design methodology. I use the 3 tier architecture in which I have components in the presentation layer, the business layer, and the data access layer.
    You are definately on the right track with everything in your architecture but there are blatent problems that could be addressed.

    The 3 tiers in your architecture are mixed up as far as I can see.

    Your Presentation is tied to your database through column names, and form names. You couldnt change your database without changing your presentation. You cant change your presentation without changing your database. I find the way you have done this to be extremely difficult to use.

    You have actual sql in your controller that is passed into your "DAO". This means you cant change your database without changing your controller.

    Quote Originally Posted by Tony Marston
    I do not have 'flex points'. I have business logic in the business layer and data access logic in the data access layer. The purpose of a data access layer is so that I can switch databases whenever I wish. My code fulfills that purpose, therefore it cannot be wrong.
    Agreed, you dont have flex point anywhere.

    The purpose of a data access layer is to "encapsulate" communication with the data source. Again, having sql in your controller screws this up.

    Quote Originally Posted by Tony Marston
    Flex points do not appear in any of the design philosophies which I read, therefore I do not consider them to be a 'requirement'. I have written code which demonstrates the use of encapsulation, inheritance and polymorhism, and as these are the primary principles of OOP my code is therefore OO. It may not be your particular brand of OO, but that is irrelevant (IMHO).
    Your code is not OO just because it demonstates the use of encapsulation, inheritance and polymorhism. Almost your entire architecture uses procedural functions (which isnt always a bad thing) and require_once style forwarding to abstracted "Transaction Controllers" that are procedural if/else scripts.

    Why not make these transaction controllers classes? (Im refering to files like std.list1.inc). Ill bet you could refactor these alot.

  6. #81
    SitePoint Wizard
    Join Date
    Aug 2004
    Location
    California
    Posts
    1,672
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    My thoughts on the original post: Sometimes you should use separate Mapper and sometimes you don't need to. But if you like Mappers by all means use them always. And if you don't, you'll be fine without them.

    To MickoZ I'd say: Keep finding those practices that allow you to spend the least amount of time writing and maintaining software. The goal is to program as little as possible. That will hopefully maximize the time you can spend with the people you care about.

    Emily Litella question: What's all this fuss about "development shurtcuts"? It's bad enough that most programmers have no sense of style, but do we have to cut their shirts? I think their shirts look find just the way they are...

    Oh. I'm sorry. Never mind.

  7. #82
    SitePoint Addict
    Join Date
    Oct 2004
    Location
    Sutton, Surrey
    Posts
    259
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Brenden Vickery
    Having 100 or so functions in a class is a serious bad code smell. Doing these things and refactoring will drop the amount of code in your architecture by a ton.
    Really? I've never seen anything written in the principles of OOP that says a class must not have more than 'n' methods or 'n' properties, so as far as I am concerned that rule does not exist and so I choose to ignore it. It is an artificial rule designed by someone who likes to add complexity to the problem.
    The definition of encapsulation is quite clear - all the properties and methods for an object must go into a single class.

    Quote Originally Posted by Brenden Vickery
    You are definately on the right track with everything in your architecture, but there are blatent problems that could be addressed.
    The 3 tiers in your architecture are mixed up as far as I can see.
    Your Presentation is tied to your database through column names, and form names. You couldnt change your database without changing your presentation. You cant change your presentation without changing your database. I find the way you have done this to be extremely difficult to use.
    My presentation layer is not tied to my database, nor is my business layer. The only layer which has physical communication with any database - by using the database APIs - is my data access layer. I am therefore able to switch from one dbms engine to another simply by switching the component in my data access layer. This is what the 3-Tier architecture is all about, and I have implemented it correctly.

    If it comes to changing the structure of a table by adding or removing fields, then I agree that I have to make changes in my presentation and business layers, but such changes are extremely small being limited to adding or removing a field name from a simple list.

    This is NOT a weakness in my design, it is a fact of life. You cannot write a business object that does not have knowledge of the data it has to work with, nor can you write a presentation layer that does not have knowledge of which fields to place where, and with what HTML control. It is simply not possible to write software which does not have knowledge of which fields exist in the database, therefore changes in the physical structure of the database will require changes in the software's knowledge of the database.

    I have worked with several languages over the past 20 years that have used data dictionaries (aka application models) where the dictionary is a representation of the physical database. It is imperative that the dictionary and the database are kept synchronised - if you make changes to one without making corresponding changes to the other the software will fail.

    What I have done is to place a mini data dictionary within each business object which simply contains the database engine name, the database name, the table name, and a list of fields. So if I change the physical structure of the database I must also change the data dictionary.

    Quote Originally Posted by Brenden Vickery
    You have actual sql in your controller that is passed into your "DAO". This means you cant change your database without changing your controller.
    Wrong! I have components of sql statements in my presentation layer, but these are not built into complete queries until they are processed within my DAO. If a different DAO needs to organise those components in a differet way, then that is handled within the DAO and is completely invisible to both the presentation and business layers.

    Quote Originally Posted by Brenden Vickery
    Your code is not OO just because it demonstates the use of encapsulation, inheritance and polymorhism. Almost your entire architecture uses procedural functions (which isnt always a bad thing) and require_once style forwarding to abstracted "Transaction Controllers" that are procedural if/else scripts.

    Why not make these transaction controllers classes? (Im refering to files like std.list1.inc). Ill bet you could refactor these alot.
    I never claimed that my entire infrastructure was OO, just my business and data access layers. I have a lot of procedural functions because there is absolutely no benefit in making them non-procedural. They work just fine as they are, and they would not work any better if I changed them, so why change them? 'If it ain't broke don't fix it' is an old, wise saying that comes to mind.

  8. #83
    SitePoint Addict
    Join Date
    Oct 2004
    Location
    Sutton, Surrey
    Posts
    259
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Brended Vickery
    Having 100 or so functions in a class is a serious bad code smell. Doing these things and refactoring will drop the amount of code in your architecture by a ton.
    Surely it will not reduce te amount of code, but simply move it from one large class to a series of smaller classes. But then I will have to have extra code to instantiate and communicate with these extra classes, so the end result will not be LESS code but MORE code, and more complex code at that. I think I shall ignore your advice and stick to the KISS principle.

  9. #84
    Non-Member
    Join Date
    Oct 2004
    Location
    downtown
    Posts
    145
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Really? I've never seen anything written in the principles of OOP that says a class must not have more than 'n' methods or 'n' properties, so as far as I am concerned that rule does not exist and so I choose to ignore it. It is an artificial rule designed by someone who likes to add complexity to the problem.
    Likewise I've yet to read anything that says you must have x ammount of class methods and no more though I can see the logic, or should that be ill-logic of having a large ammount of class mehods in one class.

    This is better known as a 'GOD' class and has been discussed before if you care to search?

    The definition of encapsulation is quite clear - all the properties and methods for an object must go into a single class.
    If there is one purpose of the class yes, but as Lastcraft says what'd you do if you have to send an email for example? I for one know this much that that'd require a seperate class. Because of this, it doesn't suppose you are breaking encapsulation.

    I would recommend you read this thread below

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

    If it comes to changing the structure of a table by adding or removing fields, then I agree that I have to make changes in my presentation and business layers, but such changes are extremely small being limited to adding or removing a field name from a simple list.
    This is rediculous. Doesn't really matter how much of a change you'd need to make, if you had to change your database schema, and then have a dependency in your presentation which'd have to be changed as well, this is breaking encapsulation as well.

    There is no clear seperation of concerns there. Period, regardless of how much or little you have to change. Also complicates the maintenance of the presentation in my view?

    This is NOT a weakness in my design, it is a fact of life.
    If it's a fact of life, then how come I can alter a database schema and in no way effect the template(s) I use? If I had to alter the database schema, only other thing that needs to be altered would be the models, ie

    PHP Code:
    class User {
    public 
    $id;
    public 
    $date;
    public 
    $username;
    public 
    $password;
     
    public function 
    __construct() {
    }
    public function 
    get() {
    }
    public function 
    insert() {
    }
    public function 
    update() {
    }
    public function 
    delete() {
    }
    ...
    public function 
    get_param$param ) {
    return 
    $this -> $param;
    }

    So I need to change the properties of this class, and maybe alter the class method 'get_param()' but the presentation need not change.

    A rule I use is that is a layer directly interacts with the presentation, use either getters (as I have in above script) or use a helper class instead, other that that, if the layer is lower down then use properties directly.

    If you use a helper class you also do not need to alter the presentation

  10. #85
    Non-Member
    Join Date
    Oct 2004
    Location
    downtown
    Posts
    145
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Here is an example of a helper class,

    PHP Code:
    # example model domain 'helper'
    class User 
        var 
    $id
        var 
    $name
        function 
    getId() { 
            return 
    $this->id
        } 
        function 
    getName() { 
            return 
    $this->name
        } 
        
    // All of your setters aswell. 
        // This would contain all of you domain logic functions aswell 

    // Helpers only have functions relating to the view 
    class UserHelper 
        private 
    $user
        function 
    UserHelper(User $user) { 
            
    $this->user $user
        } 
        function 
    getName() { 
            return 
    $this->user->getName(); 
        } 
        function 
    getId() { 
            return 
    $this->user->getId(); 
        } 

    $user getUserFromDatabaseSomehow(); 
    // Carry out domainLogic 
    $this->view = new UserEditView(new UserHelper($user)); 
    Brendan or Austin posted it a while back, cannot remember exactly who, but I use it now and it's a sound judgement btw

  11. #86
    SitePoint Evangelist
    Join Date
    Nov 2001
    Location
    UK
    Posts
    553
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Tony Marston
    Really? I've never seen anything written in the principles of OOP that says a class must not have more than 'n' methods or 'n' properties, so as far as I am concerned that rule does not exist and so I choose to ignore it. It is an artificial rule designed by someone who likes to add complexity to the problem.
    Quite right, there is no written rule as such - it's completely subjective. But when a class reaches the size of the one 'Brenden Vickery' posted, I begin to think something is going horribly wrong. I'm only learning, myself, so I won't pretend to be any sort of authority on OOP, but perhaps this link will be of some use: http://c2.com/cgi/wiki?CodeSmell

    Having read one of your earlier posts, I also feel you've misundersood what the purpose of a single User class is. A User object should represent one user, no more, no less, and should encapsulate the properties and responsibilities of the real-life object. That is to say, I (in real-life) don't have the responsibility of storing information about myself in a database - as such, a User object should be completely unaware of any database interaction. This is the One Responsibility Rule. Any code which stores or retrieves information about the user should ideally be held in another class (described as a Mapper in this thread) becuase that is a completely seperate responsibility.



    User <-> UserMapper ( <-> DAO ) <-> Database




    As I said, I am myself only learning, so correct me if I've misunderstood what I've read elsewhere.



    Off Topic:

    On an off-topic note: Tony, if your framework works for you then that's all that should matter. But (and it's a big "but") if you are going to post up all the intricate details of it on the web, surely you have to be prepared to take some criticism and advice from others?

    Lastcraft most certainly does not need me to defend him, but over the past year he has constantly and consistantly proven himself to the members of this community and you'd do well to take his advice without being offended. Whether or not you choose to follow his advice is up to you, I know I certainly will...
    Regards, Ant.

  12. #87
    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 Tony Marston
    Really? I've never seen anything written in the principles of OOP that says a class must not have more than 'n' methods or 'n' properties, so as far as I am concerned that rule does not exist and so I choose to ignore it.
    This may be worth looking at:
    http://c2.com/cgi/wiki?ManyShortMethodsPerClass

    and since this seems to be the overall subject this thread has migrated to, perhaps this as well:
    http://c2.com/cgi/wiki?FearOfAddingClasses
    Jason Sweat ZCE - jsweat_php@yahoo.com
    Book: PHP Patterns
    Good Stuff: SimpleTest PHPUnit FireFox ADOdb YUI
    Detestable (adjective): software that isn't testable.

  13. #88
    Non-Member
    Join Date
    Oct 2004
    Location
    downtown
    Posts
    145
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    You maybe need to use some deodorant as well

    http://c2.com/cgi/wiki?CodeDeodorant

    I started a new thread on the OneResponsibilityRule if anyone is interested in contributing to it. I'd be appreciated

  14. #89
    SitePoint Enthusiast MickoZ's Avatar
    Join Date
    Jul 2004
    Location
    Canada, Qc
    Posts
    42
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Version0-00e
    Here is an example of a helper class,

    PHP Code:
    # example model domain 'helper'
    class User 
        var 
    $id
        var 
    $name
        function 
    getId() { 
            return 
    $this->id
        } 
        function 
    getName() { 
            return 
    $this->name
        } 
        
    // All of your setters aswell. 
        // This would contain all of you domain logic functions aswell 

    // Helpers only have functions relating to the view 
    class UserHelper 
        private 
    $user
        function 
    UserHelper(User $user) { 
            
    $this->user $user
        } 
        function 
    getName() { 
            return 
    $this->user->getName(); 
        } 
        function 
    getId() { 
            return 
    $this->user->getId(); 
        } 

    $user getUserFromDatabaseSomehow(); 
    // Carry out domainLogic 
    $this->view = new UserEditView(new UserHelper($user)); 
    Brendan or Austin posted it a while back, cannot remember exactly who, but I use it now and it's a sound judgement btw
    Woot? But what Tony was saying is probably something like, if you add birthdate to User's property. The view has to deal with that birthdate. I can go further. If you add a property which is an unknow type (not a date, int, text or whetever field) so far, then you will have to alter your view-logic at less... it is common sense. Actually even thought I am still skeptic that I would 100% like Tony's way, when you return a generic way to represent data (here is an array, this value is a date, etc.) there is more chance you can process those data a generic way (if this is a date field to be entered -> show the form control date; etc.) But if you add an attribute to a class, I guess you have to explicitely call it.

    Else if I don't get something, can you post a pseudo-complete example (or point me to one) where we add a birthdate or something odd to an User object and we not need to alter let's say any add-edit-remove presentation page?

  15. #90
    ********* 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 Tony Marston
    ...so as far as I am concerned that rule does not exist and so I choose to ignore it.
    Are you only capable of thinking in "rules"? It's a best practice.

    Quote Originally Posted by Tony Marston
    all the properties and methods for an object must go into a single class.
    As objects are created from classes that statement does nothing except state the syntax rules of PHP. How you choose classes is the tricky bit, and noun/verb is pretty much dead and buried these days.

    Quote Originally Posted by Tony Marston
    This is what the 3-Tier architecture is all about, and I have implemented it correctly.

    If it comes to changing the structure of a table by adding or removing fields, then I agree that I have to make changes in my presentation and business layers, but such changes are extremely small being limited to adding or removing a field name from a simple list.
    Not if there is a connection between your schema and your presentation you haven't. What if you don't use an RDBMS, but a full text engine. Or the domain model is a SOAP interface on a separate server? That is not a 3-tier system and to describe it as such is to commit malpractice.

    Quote Originally Posted by Tony Marston
    This is NOT a weakness in my design, it is a fact of life. You cannot write a business object that does not have knowledge of the data it has to work with, nor can you write a presentation layer that does not have knowledge of which fields to place where, and with what HTML control.
    I have written four site architectures in the last three years. Every single one achieved the separation you claim is impossible.

    Quote Originally Posted by Tony Marston
    It is imperative that the dictionary and the database are kept synchronised - if you make changes to one without making corresponding changes to the other the software will fail.
    That's not the issue. The issue is letting this information bleed to higher layers.

    Quote Originally Posted by Tony Marston
    So if I change the physical structure of the database I must also change the data dictionary.
    It's called coupling, which is poor encapsulation.

    Quote Originally Posted by Tony Marston
    They work just fine as they are, and they would not work any better if I changed them, so why change them?
    (Self censored. Even I admit I went too far.)

    yours, Marcus
    Last edited by lastcraft; Nov 13, 2004 at 21:51. Reason: Removed gratuitous insults
    Marcus Baker
    Testing: SimpleTest, Cgreen, Fakemail
    Other: Phemto dependency injector
    Books: PHP in Action, 97 things

  16. #91
    SitePoint Addict
    Join Date
    Oct 2004
    Location
    Sutton, Surrey
    Posts
    259
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Version0-00e
    If there is one purpose of the class yes, but as Lastcraft says what'd you do if you have to send an email for example? I for one know this much that that'd require a seperate class. Because of this, it doesn't suppose you are breaking encapsulation.
    In this example I would not have the User class send an email. Instead I would have a controller which extracts the relevant information from the User class, then passes that information to an email object.

    Quote Originally Posted by Tony Marston
    If it comes to changing the structure of a table by adding or removing fields, then I agree that I have to make changes in my presentation and business layers, but such changes are extremely small being limited to adding or removing a field name from a simple list.
    Quote Originally Posted by Version0-00e
    This is rediculous. Doesn't really matter how much of a change you'd need to make, if you had to change your database schema, and then have a dependency in your presentation which'd have to be changed as well, this is breaking encapsulation as well.
    I have worked with a variety of 2nd, 3rd and 4th generation languages for over 20 years, and I have yet to see a language where the presentation layer, be it a screen or a report, does not contain a list of field names which need to be displayed, plus their individual field sizes. If you add a new field to the database then you must add that field to the screen or report layout otherwise it will be inaccessible to the user. Likewise if you remove a field from the database and do not remove it from the corresonding input screen then the user will not know that the field is no longer available, and will wonder why any data he puts into that field is not echoed back later.

    When it comes to building a screen for the user, whether it be a GUI screen or an HTML screen, you must have some method of specifying what fields are going to be displayed, in what order, what their labels are, what controls to use (e.g. text box, radio group, dropdown list, checkbox, etc). Without this knowledge your presentation layer, your screen builder, may generate screens that would not be appealing to the user.

    Quote Originally Posted by Version0-00e
    If it's a fact of life, then how come I can alter a database schema and in no way effect the template(s) I use?
    I can change the database without touching any of my XSL templates, but I still have to amend the list of fields which I want that template to display.

    How do you instruct your templating system on which fields to display, what size, in which order, what field labels to use, what controls to use? Or does it decide for itself, by magic?

    Quote Originally Posted by Version0-00e
    If I had to alter the database schema, only other thing that needs to be altered would be the models, ie
    PHP Code:
    class User {
    public 
    $id;
    public 
    $date;
    public 
    $username;
    public 
    $password;

    public function 
    __construct() {
    }
    public function 
    get() {
    }
    public function 
    insert() {
    }
    public function 
    update() {
    }
    public function 
    delete() {
    }
    ...
    public function 
    get_param$param ) {
    return 
    $this -> $param;
    }

    In my infrastructure if I add or remove fields from the database all I have to amend within the class is the $fieldspec array which contains the list of field names. I do not have to amend any other class properties or methods at all.

    Quote Originally Posted by Version0-00e
    A rule I use is that is a layer directly interacts with the presentation, use either getters (as I have in above script) or use a helper class instead, other that that, if the layer is lower down then use properties directly.
    My business layer objects are only connected to the presentation layer via a controller which sucks data out of the object, converts it into XML format, then performs an XSL transformation to produce XHTML output. I do not use a separate getter for each field, and a helper class in this instance would simply be an unnecessary layer of complexity.

  17. #92
    SitePoint Addict
    Join Date
    Oct 2004
    Location
    Sutton, Surrey
    Posts
    259
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Tony Marston
    Really? I've never seen anything written in the principles of OOP that says a class must not have more than 'n' methods or 'n' properties, so as far as I am concerned that rule does not exist and so I choose to ignore it. It is an artificial rule designed by someone who likes to add complexity to the problem.
    Quote Originally Posted by AWilliams
    Quite right, there is no written rule as such - it's completely subjective. But when a class reaches the size of the one 'Brenden Vickery' posted, I begin to think something is going horribly wrong. I'm only learning, myself, so I won't pretend to be any sort of authority on OOP, but perhaps this link will be of some use: http://c2.com/cgi/wiki?CodeSmell
    If it is subjective then it is a matter of personal taste. I have read that CodeSmell article, but all it does is raise questoions. When is a class too big or too small? When does a class have too few or too many functions? When does a class have too few or two many variables? It does not give any definitive answers because ther ARE no definitive answers. Each case has to be judged on its merits. I choose to keep all my properties and methods for an object in a single class because that is what encapsulation is supposed to be about. This means that whenever I want to change that object I only have a single class to maintain. If I had that information spread over several different classes it would not only be more difficult to maintain, and would be more complex to deal with as I would have to flit from one class to another in order to get anything done. That idea has a distinct 'smell' to me.

    Quote Originally Posted by AWilliams
    Any code which stores or retrieves information about the user should ideally be held in another class (described as a Mapper in this thread) becuase that is a completely seperate responsibility.
    My User class does not interact with the database directly as this is done through a separate DAO. All sql queries are constructed and executed within the DAO. So the 'responsibility' of storing or retrieving from the database lies within the DAO, not the User class. I can achieve this without a separate mapper class.
    Last edited by Tony Marston; Nov 13, 2004 at 12:50.

  18. #93
    Non-Member
    Join Date
    Oct 2004
    Location
    downtown
    Posts
    145
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    If I had that information spread over several different classes it would not only be more difficult to maintain, and would be more complex to deal with as I would have to flit from one class to another in order to get anything done.
    Would be be true in that case if there were poor communication between the class(es) in question. I suggested a forum thread that helped to explain this basic fact, I'd take a guess that you've not read it yet?

    But regardless this is the last time I'm taking time out to read this thread as I see it's pointless in my view to continue as you have no real interest is what others have to discuss

  19. #94
    SitePoint Addict JNKlein's Avatar
    Join Date
    Sep 2004
    Location
    New York, NY
    Posts
    258
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by lastcraft
    I have written four site architectures in the last three years. Every single one achieved the separation you claim is impossible.
    Any opensource that we can look at?

  20. #95
    SitePoint Addict
    Join Date
    Oct 2004
    Location
    Sutton, Surrey
    Posts
    259
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by lastcraft
    Quote Originally Posted by Tony Marston
    ...so as far as I am concerned that rule does not exist and so I choose to ignore it.
    Are you only capable of thinking in "rules"? It's a best practice.
    But in my many years of experience I have encountered many groups of developers who each have their own version of 'best practice'. All too often one group thinks that their version of 'best practice' is so good that it must be adopted by everybody, so these 'guidelines' gradually become 'rules', and anyone who disagrees must be cast down as a heretic. If it is not a concrete rule then why should I follow it?

    Quote Originally Posted by lastcraft
    Quote Originally Posted by Tony marston
    If it comes to changing the structure of a table by adding or removing fields, then I agree that I have to make changes in my presentation and business layers...
    Not if there is a connection between your schema and your presentation you haven't. That is not a 3-tier system and to describe it as such is to commit malpractice. I have written four site architectures in the last three years. Every single one achieved the separation you claim is impossible.
    It IS a 3-tier system because each tier has distinct has separate responsibilities. AFAIAA it is impossible to add a field to a database table without affecting a business object, otherwise how does it know what business rules to apply to that field? It also requires a change to the presentation layer otherwise how would it know where to paint it on the screen, what control to use, what label to use.

    If you have a system where you can add or remove fields from a database table without amending any business or presentation objects then I'm sure lots of us reading this thread would like to share in your secret.

    Quote Originally Posted by lastcraft
    Quote Originally Posted by Tony Marston
    So if I change the physical structure of the database I must also change the data dictionary.
    It's called coupling, which is poor encapsulation.
    Then you have obviously not used any dictionary-based systems othewise you would know that keeping the dictionary synchronsied with the physical database is of paramount importance.

    Quote Originally Posted by lastcraft
    If you are completely ignorant of alternate solutions (and you have a pretty minimal understanding of OO as far as I can make out, never mind enterprise patterns) then how would you ever know?
    I am not ignorant of alternative solutions, it is just that I have seen too many of them which do not 'smell' right and which ultimately end up in failed or second-rate projects. I have seen what happens when a team of so-called 'experts' tries to build a system using all the OO 'best practices' and design patterns they can think of, and the result was not pretty. They spent 3 man-years building an infrastructure that did not work and which caused the client to cancel a multi-million pound contract. I turned round and built an infrastructure which satisfied the client's requirements in 2 man-weeks. So forgive me if I tend to take the advice of 'experts' with a pinch of salt.

    Quote Originally Posted by lastcraft
    It's pretty unpleasant, although mercifully rare, to come across someone who claims to be right all the time on scanty knowledge alone. To find someone who is proud of that ignorance, and refuses to learn even when things are tediously explained to them or further reading pointed out, is astonishing.
    I have never said that my method is the 'right' way any more that I have said that your method is the 'wrong' way. I have merely said that I have found a 'different' way. You have not commented on the fact that my way works, or how easy it is to create and amend transactions, just that it is 'different', and because it is not 'your' way then it must be the 'wrong' way.

    If someone is capable of making a constructive suggestion on how I can improve my infrastructure, or make it more efficient, or improve it in some other way then I will be more than happy to listen. But all the while you restrict your comments to 'you must not do it *that* way, you must do it *this* way' I will not listen. If I did things your way then I would be no better than you, and I am not convinced that 'your' way is the 'best' way. In an attempt to find something which is 'better' I have to start with something which is 'different', and it is this difference which seems to upset you.

  21. #96
    SitePoint Addict
    Join Date
    Oct 2004
    Location
    Sutton, Surrey
    Posts
    259
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Version0-00e
    But regardless this is the last time I'm taking time out to read this thread as I see it's pointless in my view to continue as you have no real interest is what others have to discuss.
    That is because you having nothing constructive to say. You wish me to change the way I do things so that they are more like yours, but why on earth should I want to step back into the dark ages?

  22. #97
    SitePoint Enthusiast MickoZ's Avatar
    Join Date
    Jul 2004
    Location
    Canada, Qc
    Posts
    42
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Just to challenge you a little Tony, how hard will it be for you in your sample application to follow this. (I just gone to play with it a little):

    In Adding an user screen (comment, request, etc.):

    - I do not like the fact that when you call the popup, the value that is already selected is not selected in the popup, will it be hard for you to add this?

    - I do not like the fact that in the popup, I can pick two value, when in fact a person in your model seem to be able to be part of only one organisation. Suggestion: use radio button to show that the choice is single, or allow multiple selection and thread it accordingly.

    - I guess the only way to go back in the new form when going into that popup mode, is to use the navigation section (on top) and click on new in case we want to cancel everything.

    ---------------

    I know sometime some stuff doesn't look obvious or are not understood by the mass and when you dare to challenge them, they go against you. But then, in the end your way sometime seem to be more efficient (time, security, solution quality, etc.). You documented everything and that is nice, not a lot of people has done that this way.

    I guess the problem here is people are trying to challenge the OO principle versus the architecture and your architecture is not 100% OO (and you even said so it was not, but people seem to forget that.)

    I would say [withouth think much] that Tony's architecture use OO for structuring, etc. and he tries to make his own way to do stuff with a bit of creativity. He is maybe not separating everything and there is probably limitation with some stuff. But like any software, sometime limitation is good. ex: he choose to do popup a certains way, etc. maybe he can create a popup_style_1, popup_style_2 then simply say to his script which kind of popup to use (I have not verify that but I suspect from what I saw he done that this is the way he will do it)

    I would like the "smart people" here not take personally or badly any critic from Tony and if you want to prove wrong, let's get concret, pragmatic, direct, etc.

    He might challenge you and he might even be wrong![!!!] But I am sure that if you can prove his architecture wrong, he will try to improve it.

    To do this, you have to find counter example where his architecture won't work or won't be efficient. Theory is nice, babbling is nice, we all like it somehow (we are a bit philsophical about software, aren't we in our own form? )

    I have 20 years in software development might mean something or not. I have done 10 websites might mean something or not. etc. Even if Tony had 2 years in software development I would handle it the same way I guess (I don't get much impressed with experience often... but of course good experience that helped to improve upward beside stay at the same level or go a level below is a good sign)

  23. #98
    SitePoint Addict
    Join Date
    Oct 2004
    Location
    Sutton, Surrey
    Posts
    259
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by MickoZ
    I do not like the fact that when you call the popup, the value that is already selected is not selected in the popup, will it be hard for you to add this?
    In the 12 years that I have been writing popups for systems I have never come across the requirement to show the current selection when the popup is invoked. I have also never seen it in any one else's popups. Surely the current selection is visible before you select the popup, and you only select the popup when you want to change the current selection.

    Quote Originally Posted by MickoZ
    I do not like the fact that in the popup, I can pick two value, when in fact a person in your model seem to be able to be part of only one organisation. Suggestion: use radio button to show that the choice is single, or allow multiple selection and thread it accordingly.
    You may appear to be able to select more than one entry in the popup, but after returning to the previous form it should be obvious that only one has actually been selected. This is because all popups will allow multiple selections, but it depends on the calling form whether it will actually accept multiple selections or not. I could get the calling form to pass a message to the popup to only allow a single selection, but it does not seem that important. Once users become aware of how popups work this becomes a very minor point.

    Quote Originally Posted by MickoZ
    I guess the only way to go back in the new form when going into that popup mode, is to use the navigation section (on top) and click on new in case we want to cancel everything.
    In screens which update the database I have a CANCEL button which acts as an alternative to SUBMIT. In screens which do not update the database - such as the popup - I used to have a FINISH button which did the same as CANCEL, but I was told by an 'expert' that this would confuse the users as they would prefer to use the browser's BACK button (or, as you have discovered, any one of the buttons on the menu bar).

    Congratulations! You are the first person to tell me this 'expert' was wrong!

    Quote Originally Posted by MickoZ
    I guess the problem here is people are trying to challenge the OO principle versus the architecture and your architecture is not 100% OO (and you even said so it was not, but people seem to forget that.)
    How come you spotted that but nobody else seemed to?

    How come nobody has commented on my use of XSL stylesheets where a single stylesheet can handle multiple screens? How come nobody has commented on the fact that of the 14 elements within my infrastructure 9 of them are totally resuable and 2 others are generated at runtime, leaving just 3 elements to be coded by the developer?

    Quote Originally Posted by MickoZ
    maybe he can create a popup_style_1, popup_style_2 then simply say to his script which kind of popup to use.
    Yes, that is eminently do-able. Maybe I will do that when I have some time.

  24. #99
    SitePoint Enthusiast MickoZ's Avatar
    Join Date
    Jul 2004
    Location
    Canada, Qc
    Posts
    42
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    1. About popup passing value: well if your popup is of style "list" or if you use a combobox, it's behavior should be the same. The only difference is that the popup is external (whetever how you do your popup). Of course it depends on the kind of popup probably. In one where you pick a new value, it depends and can be acceptable.

    2. I think letting the user select one or multiple items should be an important property (call it usability?!) And if your model is done the way I think, then it should not be a major problem adding that feature. radio != checkbox.

    3. There is no good way or what about expert. I find stuff confusing in your sample apps (maybe with the tree stuff). However an option to "close" the popup withouth selecting any value is quite important. For now your popup act in the same screen. But it could be a real windows popup. It could also be in the same screen. I like to talk in concept and that is what your popup system is/can_be.

    4. Personally I have not commented on your XSL, etc. stuff because well I am not familiar (even thought I know approximately how they should be used). Why people haven't? Because they see it in a developper kind of way. You are smart enough to ask question and know the answer probably, but sometime asking them to be sure is great. I guess other might have see this, but I think since you talk about OO, they try to judge it as OO and that is why there is miscommunication. Like I think you said (and I said[,and many other people]) programming is an art. You somehow invented (inspired by other stuff you been doing/saw/etc.) a way to do things. You put constraint (i.e. your system work X way, if an user want it's popup absolutely in the same screen, etc. you restrain this -- sure you can have a way to do it, but to stay concistent you maked a system and you try to follow it probably to save time -- personally my ideal system would allow me to include 1, 10 forms in one screen of the same type of widget, etc. But modeling it perfectly will be hard and I am not going there [yet?])

    5. It should take you 10 minutes to create new style do it now ;-) *jk*
    -------

    Another thing I noticed... I guess this has to do with the session (and you can probably easily handle this?)... the navigation place dissapeared after sometime I let my browser idle... no matter where I did go, it was out of there, I guess your navigation is managed with your session or something. I could probably try to reproduce that, but I guess you are aware that this can happen [and accept it]?

  25. #100
    SitePoint Addict
    Join Date
    Oct 2004
    Location
    Sutton, Surrey
    Posts
    259
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by MickoZ
    However an option to "close" the popup withouth selecting any value is quite important.
    Done. I've added a FINISH button to the relevant screens.

    Quote Originally Posted by MickoZ
    Another thing I noticed... I guess this has to do with the session (and you can probably easily handle this?)... the navigation place dissapeared after sometime I let my browser idle... no matter where I did go, it was out of there, I guess your navigation is managed with your session or something.
    Yes, the navigation information is stored in the session data, and I have seen it happen a few times over the years, but I can never reproduce it on demand


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
  •