SitePoint Sponsor

User Tag List

Results 1 to 12 of 12
  1. #1
    SitePoint Zealot
    Join Date
    Apr 2010
    Posts
    106
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    User Action - singleton

    Hi,

    I've been thinking that I would like to decouple the User object from any actions that they are allowed to do. Because I don't know how many actions a user will do, I was thinking about implementing a singleton class.

    A quick example:

    PHP Code:
    <?php
    class User {
        private 
    $id;
        private 
    $firstname;
        private 
    $lastname;
        private 
    $email;
        
        public function 
    __construct($id$firstname$lastname) {
            
    $this->id $id;
            
    $this->firstname $firstname;
            
    $this->lastname $lastname;
        }
    }

    class 
    UserAction {
        private static 
    $instance null;
        private 
    $user;
        
        private function 
    __construct(User $user) {
            
    $this->user $user;
        }
        
        public static function 
    getInstance(User $user) {
            if (
    $instance == null) {
                return 
    self::$instance = new UserAction($user);
            } else {
                return 
    self::$instance;
            }
        }
        
        public function 
    emailBuddy($userId) {
            
    //etc..
        
    }
        
        public function 
    updateAccount() {
            
    //etc..
        
    }
        
        public function 
    postNews() {
            
    //etc..
        
    }

        
    //many many more action methods....
    }
    ?>
    As you can see, multiple actions could occur. If I were not to use a singleton than a new UserAction object would have to be created every time an action occurs.

    Best case scenario would be that a user only did one action, no exceptions were thrown / if statement fails (cause the application to change behavior) and no other class called a user action method.

    This isn't an actual project, just something I thought about. I would like to see how a non singleton approach would be taken. I also remember someone saying something about how singleton classes cannot be tested? Or something around that nature.

    Thanks

  2. #2
    SitePoint Wizard silver trophy kyberfabrikken's Avatar
    Join Date
    Jun 2004
    Location
    Copenhagen, Denmark
    Posts
    6,157
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by proxi View Post
    If I were not to use a singleton than a new UserAction object would have to be created every time an action occurs.
    You seem to imply that you think that would be a problem. What makes you think that?

  3. #3
    PHP Guru lampcms.com's Avatar
    Join Date
    Jan 2009
    Posts
    921
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Usually the UserObject should be a singleton.

    The objects that take objUser as a parameter don't really have to be singletons.

    It's up to you how you implement singleton pattern, the getInstance() will work, there are also registry and dependency injection patterns that can produce a single instance of object.
    My project: Open source Q&A
    (similar to StackOverflow)
    powered by php+MongoDB
    Source on github, collaborators welcome!

  4. #4
    ********* 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 lampcms.com View Post
    Usually the UserObject should be a singleton.
    Why?

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

  5. #5
    PHP Guru lampcms.com's Avatar
    Join Date
    Jan 2009
    Posts
    921
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Because if it's not a singleton then potentially 2 different objects may be created during the execution of your program that represent the same user. Then changes to one object are not reflecting the second object. By singleton I mean a single instance of the user object that represent the same user. Of cause there could be many user objects, each representing different user.
    My project: Open source Q&A
    (similar to StackOverflow)
    powered by php+MongoDB
    Source on github, collaborators welcome!

  6. #6
    Utopia, Inc. silver trophy
    ScallioXTX's Avatar
    Join Date
    Aug 2008
    Location
    The Netherlands
    Posts
    9,061
    Mentioned
    153 Post(s)
    Tagged
    2 Thread(s)
    Quote Originally Posted by lampcms.com View Post
    Because if it's not a singleton then potentially 2 different objects may be created during the execution of your program that represent the same user. Then changes to one object are not reflecting the second object. By singleton I mean a single instance of the user object that represent the same user. Of cause there could be many user objects, each representing different user.
    If only one user is allowed, then how can user A create a new user, user B?

    I think you're confusing User with Authentication System ...
    Rémon - Hosting Advisor

    SitePoint forums will switch to Discourse soon! Make sure you're ready for it!

    Minimal Bookmarks Tree
    My Google Chrome extension: browsing bookmarks made easy

  7. #7
    PHP Guru lampcms.com's Avatar
    Join Date
    Jan 2009
    Posts
    921
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I am not sure what you mean by user A create user B?
    Why one user object need to create another user object?
    Maybe we are talking about different scenarios. I was just talking generally that user objects in general should follow singleton pattern, meaning only one user object allowed to represent the same user. Different users of cause should have different objects.
    My project: Open source Q&A
    (similar to StackOverflow)
    powered by php+MongoDB
    Source on github, collaborators welcome!

  8. #8
    Utopia, Inc. silver trophy
    ScallioXTX's Avatar
    Join Date
    Aug 2008
    Location
    The Netherlands
    Posts
    9,061
    Mentioned
    153 Post(s)
    Tagged
    2 Thread(s)
    Quote Originally Posted by lampcms.com View Post
    Maybe we are talking about different scenarios. I was just talking generally that user objects in general should follow singleton pattern, meaning only one user object allowed to represent the same user. Different users of cause should have different objects.
    Ah, that wasn't clear in your previous post. We're on the same page now
    Rémon - Hosting Advisor

    SitePoint forums will switch to Discourse soon! Make sure you're ready for it!

    Minimal Bookmarks Tree
    My Google Chrome extension: browsing bookmarks made easy

  9. #9
    SitePoint Zealot
    Join Date
    Apr 2010
    Posts
    106
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Well a User object can be created many different ways. A few are:

    -Login
    -A collection of User objects
    -By Id
    etc..

    For that though, I use a factory.

    Which leads me to my next question.

    I was thinking about passing a DTO to the factory through the constructor to allow the creation of users. Currently, the factory extends a DTO class which inherits all connections (I use MySQL and MongoDB). Through the factory I just do something like this:

    PHP Code:
    class UserFactory extends ApplicationDTO {
      
    //...
      
    public function login($email$password) {
        
    $mysql $this->get('mysql'); // I can now use PDO to access a database
        //or maybe I want to use mongo db?
        
    $mongo $this->get('mongo');

        
    //use $mysql / $mongo to execute a query...
        //etc ...
      
    }
      
    //...


    The only thing I don't like about the approach is that I have sql all over the factory. I was thinking about abstracting that and passing the class to the factory through the constructor.

    What do you guys think?

  10. #10
    SitePoint Addict Mastodont's Avatar
    Join Date
    Mar 2007
    Location
    Czech Republic
    Posts
    375
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I think that Factory should create and return instances, method Login belongs to another class.

    Factory extending DTO is another lapse, IMHO. And DTO (if it is really Data transfer object) should not inherit connections. DTO should be a serializable value box.

    Passing the DAO class to the factory through the constructor is good idea.

  11. #11
    SitePoint Zealot
    Join Date
    Apr 2010
    Posts
    106
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Sorry, I get the DTO / DAO confused.

    The factory is a good place I think. Consider this:

    PHP Code:
    class UserFactory {

        public function 
    login($email$password) {
            
    $stmt $this->dao->login($email$password);

            if (
    $stmt != null) {
                return 
    $this->create($stmt);
            }
            throw new 
    Exception('Incorrect credentials');
        }
        
        public function 
    byId($userId) {
            
    $stmt $this->dao->byId($userId);

            if (
    $stmt != null) {
                return 
    $this->create($stmt);
            }
            throw new 
    Exception('User ID not found');
        }
        
        private function 
    create(PDOStatement $stmt) {
            
    $user $stmt->fetch(PDO::FETCH_ASSOC);
        
            return new 
    User($user['fname'], $user['lname'], $user['email']);
        }
    }

    class 
    LogIn extends ApplicationController {
        
        public function 
    defaultAction() {
            
    $request $this->getRequest();
            
            if (
    $request->isPost()) {
                
    $email $request->param('email');
                
    $password $request->param('password');
                
    $uf = new UserFactory();
                
                try {
                    
    $user $uf->login($email$password);
                    
                    
    //etc....
                
    } catch(Exception $e) {
                    
    // Unable to login
                
    }
            }
        }

    Although right now I don't have it implemented this way. The SQL is mixed in with the factory but the logic is the same.

    What do you think?

  12. #12
    SitePoint Wizard bronze trophy
    Join Date
    Jul 2006
    Location
    Augusta, Georgia, United States
    Posts
    4,147
    Mentioned
    16 Post(s)
    Tagged
    3 Thread(s)
    It seems like you would like to be able to change the DB, while adhering to the same interface. In that case it only makes sense to actually use some type interface that hosts all the user specific business transactions. This will allow the two to be interchanged, but define the details of getting the data differently. Others will also be able to be easily added to the work flow if necessary, without changing any application level, controller code.

    PHP Code:
    interface IUserDAO {
        public function 
    login($email,$password);
        public function 
    byId($userId);
    }

    class 
    MongoUserDAO implements IUserDAO {
        public function 
    login($email,$password) {
            
    /* mongo specific login implementation */
        
    }
        public function 
    byId($userId) {
            
    /* mongo specific fetch user */
        
    }
    }

    class 
    MySQLUserDAO implements IUserDAO {
        public function 
    login($email,$password) {
            
    /* mysql specific login implementation */
        
    }
        public function 
    byId($userId) {
            
    /* mysql specific fetch user */
        
    }



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
  •