SitePoint Sponsor

User Tag List

Page 13 of 16 FirstFirst ... 3910111213141516 LastLast
Results 301 to 325 of 397
  1. #301
    SitePoint Zealot Overunner's Avatar
    Join Date
    Mar 2004
    Location
    Sweden
    Posts
    180
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by 33degrees
    My inclination would be to use a Config class, with implementations for different file formats/database access etc., and either passing that to the mapper, or having it return an array which is then passed to the mapper. In the case of XML files, The Config object could be serialized to avoid having to parse the file each time it's used.
    How about the Config class reads a config file and creates a bunch of definitions.
    PHP Code:
    foreach($config as $name => $value)
      
    define($name$value); 
    Then we don't have to worry about passing the config object around since the defined constants are accessible everywhere. But having global constants would perhaps break the layering?
    Quote Originally Posted by arborint
    Please contribute an XML or INI Reader if you have one and we can use it as a start.
    I've put together an extremely simple INI-parser. Intended use:
    PHP Code:
    $config = new Config(new IniFileReader('config.ini'));

    // ------------------
    class Config
    {
      var 
    $configs = array();

      function 
    Config(&$reader)
      {
        
    $configs $reader->parse();
      }

    Things left to be done:
    * Check if the filename given to the reader actually is a .ini-file
    * Check if the file actually exists
    * ... probably some other checks...
    Attached Files Attached Files

  2. #302
    Non-Member
    Join Date
    Jan 2003
    Posts
    5,748
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Here is one method that I use to read from an XML file in regards to configuration parameters.

    PHP Code:
    interface IAdaptable {
            public function 
    getNodes();
            public function 
    push$fragment );
        }

    abstract class 
    AbstractAdaptable implements IAdaptable {
            protected 
    $nodes;
            protected 
    $fragment;
            
            public function 
    getNodes() {
                return 
    $this -> nodes;
            }
        }
        
        abstract class 
    AbstractDecoratableAdaptable implements IAdaptable {
            protected 
    $fragment;
            
            abstract public function 
    __construct$decoratable );
            
            public function 
    getNodes() {
                return 
    $this -> decoratable -> getNodes();
            }
        }
        
        abstract class 
    AbstractTraverseAdaptable implements IAdaptable {
            protected 
    $nodes;
            protected 
    $fragment;
            
            abstract public function 
    __construct$fragment );
            
            public function 
    getNodes() {
                return 
    $this -> nodes;
            }
            
            abstract private function 
    traverseIComponent $composite$fragment );
        }

    interface 
    IWalker {
            public function 
    __construct$children );
            public function 
    walkIAdaptable $adapter );
        }

    class 
    XmlNodeListWalker implements IWalker {
            private 
    $children;
            
            public function 
    __construct$children ) {
                if( !
    $children instanceof DomNodeList ) {
                    throw new 
    IllegalParameterException'thrown exception on, expected parameter(s) not found.' );
                }
                
    $this -> children $children;
            }
            
            public function 
    walkIAdaptable $adapter ) {
                foreach( 
    $this -> children as $child ) {
                    if( 
    $child instanceof DomElement ) {
                        
    $adapter -> push$child );
                        try {
                            
    $walker = new XmlNodeListWalker$child -> childNodes );
                            
    $walker -> walk$adapter );
                        } catch( 
    IllegalParameterException $e ) {
                            die( 
    $e -> getMessage() );
                        }
                    }
                }
            }
        }

    class 
    Config {
            public function 
    __construct() {}
            
            static public function 
    load$filename ) {
                if( 
    file_exists$filename ) && is_file$filename ) ) {
                    
    $dom = new DomDocument();
                    
    $dom -> load$filename );
                    return 
    $dom;
                }
                return 
    false;
            }
            
            static public function 
    fetch$parameters ) {
                static 
    $cfg;
                if( !
    is_array$cfg ) ) { 
                    
    $dom Config::loadApplication::config );
                    if( 
    $dom instanceof DomDocument ) { 
                        
    $walker = new XmlNodeListWalker$dom -> documentElement -> childNodes );
                        
    $adapter = new ConfigDecoratableAdapter( new ConfigAdapter() );
                        
    $walker -> walk$adapter ); 
                        
                        
    $cfg $adapter -> getNodes(); 
                    } 
                } 
                if( isset( 
    $cfg[$parameters[0]][$parameters[1]] ) ) {
                    return 
    $cfg[$parameters[0]][$parameters[1]];
                }
                return 
    false;
            }
        }
        
        class 
    ConfigAdapter extends AbstractAdaptable {
            public function 
    __construct() {
                
    $this -> nodes = array();
            }
            
            public function 
    push$fragment ) { 
                if( 
    $fragment -> item) ) {
                    
    $key $fragment -> item) -> parentNode -> nodeName
                    foreach( 
    $fragment as $child ) {
                        if( 
    $child -> nodeType == XML_ELEMENT_NODE ) {
                            
    $this -> nodes[strtolower$key )][strtolower$child -> nodeName )] = $child -> nodeValue;
                        }
                    }
                }
            }
        }

        class 
    ConfigDecoratableAdapter extends AbstractDecoratableAdaptable {
            public function 
    __construct$decoratable ) {
                
    $this -> decoratable $decoratable;
            }
            
            public function 
    push$fragment ) { 
                if( 
    $fragment -> nodeType == XML_ELEMENT_NODE ) {
                    
    $this -> decoratable -> push$fragment -> childNodes );
                }
            }
        } 
    And you use it with something like this,

    PHP Code:
    class Application {
    const 
    config 'path/to/config/file';
    }

    // ...

    echo( Config::fetch( array( 'db''type' ) ) );

    // ... 
    Where the XML file is something like this,

    Code:
    <config>
    <db>
    <type>...</type>
    <host>...</host>
    <user>...</user>
    <pass>...</pass>
    <name>...</name>
    </db>
    <!-- other parameters here -->

  3. #303
    SitePoint Zealot shenkong's Avatar
    Join Date
    Sep 2004
    Location
    China
    Posts
    132
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    My entrance .
    PHP Code:
    <?php
    /**
     * 后台管理入口文件
     *
     * Copyright(c) 2005 by 陈毅鑫(深空). All rights reserved
     *
     * To contact the author write to {@link mailto:shenkong@php.net}
     * 
     * @author 陈毅鑫(深空)
     * @version $Id: admin.php,v 1.2 2005/06/03 01:17:55 shenkong Exp $ 
     * @package User Management System 
     */
    $start getTime();
    function 
    getTime() {
        
    $microtime microtime();
        
    $microtime explode(" "$microtime);
        
    $microtime $microtime[1] + $microtime[0];
        return 
    $microtime;
    }
    function 
    timePassed($start_time$length 4) {
        
    $end_time    getTime();
        
    $time_passed = ($end_time $start_time);
        
    $time_passed round($time_passed$length);
        return 
    $time_passed " s";
    }

    ob_start();
    main();
    ob_end_flush();

    /**
     * 主函数
     */
    function main() {
        
    /**
         * 定义一个错误处理常量
         */
        
    define("HOME"true);

        
    /**
         * 文件扩展名
         */
        
    define("EXT"".php");

        
    /**
         * 入口文件名
         */
        
    define("MAIN_PAGE""admin" EXT);

        
    /**
         * 根目录
         */
        
    define("ROOT_PATH"dirname(__FILE__) . DIRECTORY_SEPARATOR);

        
    /**
         * 源代码存放目录
         */
        
    define("SOURCE_PATH"ROOT_PATH "source" DIRECTORY_SEPARATOR);

        
    /**
         * 公共配置文件存放目录
         */
        
    define("COMMON_PATH"SOURCE_PATH "common" DIRECTORY_SEPARATOR);

        
    /**
         * 公共函数文件存放目录
         */
        
    define("FUNC_PATH"SOURCE_PATH "function" DIRECTORY_SEPARATOR);

        
    /**
         * 公共类库文件存放目录
         */
        
    define("CLASS_PATH"SOURCE_PATH "class" DIRECTORY_SEPARATOR);

        
    /**
         * 私有配置文件存放目录
         */
        
    define("CONFIG_PATH"SOURCE_PATH "admin" .  DIRECTORY_SEPARATOR "config" DIRECTORY_SEPARATOR);

        
    /**
         * 模块文件存放目录
         */
        
    define("MODULE_PATH"SOURCE_PATH "admin" .  DIRECTORY_SEPARATOR "module" DIRECTORY_SEPARATOR);

        
    /**
         * 载入公共配置文件
         */
        
    require_once COMMON_PATH "config.inc" EXT;
        require_once 
    COMMON_PATH "constant.inc" EXT;
        require_once 
    COMMON_PATH "permission.inc" EXT;
        require_once 
    COMMON_PATH "signal.inc" EXT;

        
    /**
         * 载入私有配置文件
         */
        
    require_once CONFIG_PATH "config.inc" EXT;
        require_once 
    CONFIG_PATH "constant.inc" EXT;
        require_once 
    CONFIG_PATH "skin.inc" EXT;

        
    /**
         * 根据公共配置文件的 DEBUG 常量定义来选择出错提示,
         * 在程序正式发布时候,应将改常量定义为 false
         */
        
    if (true == DEBUG) {
            
    error_reporting(E_ALL E_NOTICE);
        } else {
            
    error_reporting(0);
        }
        
        
    header("content-type: text/html; charset={$configs["default_charset"]}");

        
    /**
         * 开始会话,考虑数次,会话文件还是存放在系统临时目录比较安全
         */
        
    session_start();

        
    /**
         * 载入公共函数
         */
        
    loadFunc("global""errorlog");
        
    //loadFunc("errorlog");

        /**
         * 处理 HTTP 请求数据
         */
        
    $_GET  =& cleanInfo($_GET);
        
    $_POST =& cleanInfo($_POST);

        
    import("Controller""Home");

        
    $controller Controller::init($configs);

        
    $controller->execute();
    }

    /**
     * 载入库文件
     *
     * @param string $class_name
     */
    function import($class_name) {
        if (!
    is_array($class_name)) {
            
    $args func_get_args();
        } else {
            
    $args $class_name;
        }

        foreach (
    $args as $arg) {
            require_once 
    CLASS_PATH $arg ".class" EXT;
        }
    }

    /**
     * 载入函数库文件
     *
     * @param string $func_name
     */
    function loadFunc($func_name) {
        if (!
    is_array($func_name)) {
            
    $args func_get_args();
        } else {
            
    $args $func_name;
        }

        foreach (
    $args as $arg) {
            require_once 
    FUNC_PATH $arg ".func" EXT;
        }
    }

    /**
     * 载入模块文件
     *
     * @param string $module_name
     */
    function loadModule($module_name) {
        require_once 
    MODULE_PATH $module_name ".mod" EXT;
    }

    /**
     * 载入扩展文件
     *
     * @param string $extend_name
     */
    function loadExtend($extend_name) {
        
    $path implode(DIRECTORY_SEPARATORexplode("."$extend_name));
        require_once 
    EXTENT_PATH $path ".class" EXT;
    }

    ?>

  4. #304
    SitePoint Wizard
    Join Date
    Aug 2004
    Location
    California
    Posts
    1,672
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by shenkong
    My entrance .
    I believe the file that would be of interest to this list would be your Controller.class.php and maybe your config file.
    Christopher

  5. #305
    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)
    PHP Code:
    function getTime() {
        
    $microtime microtime();
        
    $microtime explode(" "$microtime);
        
    $microtime $microtime[1] + $microtime[0];
        return 
    $microtime;

    ==
    PHP Code:
    function getTime() {
        return 
    array_sum(explode(' '$microtime));


  6. #306
    SitePoint Zealot shenkong's Avatar
    Join Date
    Sep 2004
    Location
    China
    Posts
    132
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    OK, my controller
    PHP Code:
    <?php
    /** 
     * 控制器
     *
     * Copyright(c) 2005 by 陈毅鑫(深空). All rights reserved
     *
     * To contact the author write to {@link mailto:shenkong@php.net}
     * 
     * @author 陈毅鑫(深空)
     * @version $Id: Controller.class.php,v 1.5 2005/06/16 08:21:37 shenkong Exp $ 
     * @package User Management System 
     */

    defined("HOME") || header("location: error.html");

    /**
     * 控制器,从这里来指定所属模块
     *
     */
    class Controller {
        
    /**
         * 全局配置参数数组
         *
         * @var array
         */
        
    var $_configs;
        
        
    /**
         * 全局模块配置数组
         *
         * @var array
         */
        
    var $_modules;
        
        
    /**
         * 当前模块
         *
         * @var string
         */
        
    var $_module;
        
        
    /**
         * 实例化模块产生的对象
         *
         * @var object
         */
        
    var $obj;

        
    /**
         * 构造器,初始化,并实例化模块对象
         *
         * @param array $configs
         * @return object
         */
        
    function Controller(&$configs) {
            require_once 
    CONFIG_PATH "module.inc" EXT;
            
            
    $this->_configs = & $configs;
            
    $this->_modules = & $modules;
            
    $this->_module $this->getModule();
            
    $this->_modules['current'] = $this->_module;
            
            
    $module ucfirst($this->_module);
            
    loadModule($module);
            
    $this->obj = new $module($configs$modules);
        }

        
    /**
         * 初始化控制器
         *
         * @param array $configs 传递全局配置数组
         * @return object
         */
        
    function &init(&$configs) {
            static 
    $controller null;
            if (
    is_null($controller)) {
                
    $controller = & new Controller($configs);
            }
            return 
    $controller;
        }
        
        
    /**
         * 去的当前模块
         *
         * @return string
         */
        
    function getModule() {
            
    $module = isset($_GET[$this->_configs['module_name']]) ? $_GET[$this->_configs['module_name']] : $this->_configs['default_module'];
            
    $module strtolower($module);
            return 
    $this->checkModule($module);
        }
        
        
    /**
         * 检测模块是否合法
         *
         * @param string $module
         * @return string
         */
        
    function checkModule($module) {
            if (!
    array_key_exists($module$this->_modules)) {
                
    $module $this->_configs['default_module'];
            }
            return 
    $module;
        }
        
        
    /**
         * 执行模块
         *
         */
        
    function execute() {
            
    // IP Banned
            
    $ip_func "ip_" $this->_module;
            if (
    function_exists($ip_func)) {
                
    $ip $this->obj->_context->getIP();
                if (!
    $ip_func($ip)) {
                    exit(
    "IP禁止");
                }
            }
            
            
    // user permission
            
    $p $this->obj->permission;

            
    $is_display $this->_modules[$this->_module]["is_display"];
            
    $is_common  $this->_modules[$this->_module]["is_common"];

            
    $url $this->obj->_context->getURL();
            
    $url urlencode($url);

            if (
    $is_common == "n" && !$p[COMMON_VIEW_ADMIN_MODULE]) {
                
    $login MAIN_PAGE "?module=login&url=" $url;
                exit(
    '<script type="text/javascript">top.location.href="' $login '"</script>');
                
            }
            if (
    $is_display == "n" && !$p[COMMON_VIEW_HIDE_MODULE]) {
                
    $login MAIN_PAGE "?module=login&url=" $url;
                exit(
    '<script type="text/javascript">top.location.href="' $login '"</script>');
            }

            
    $this->obj->execute();
        }
    }

    ?>

  7. #307
    SitePoint Zealot shenkong's Avatar
    Join Date
    Sep 2004
    Location
    China
    Posts
    132
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by sweatje
    PHP Code:
    function getTime() {
        return 
    array_sum(explode(' 'microtime())); 

    thank you

  8. #308
    SitePoint Zealot Overunner's Avatar
    Join Date
    Mar 2004
    Location
    Sweden
    Posts
    180
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by kyberfabrikken
    authentication is a matter of identifying a person.
    authorization is a matter of figuring if a given person has the rights to do a specific thing.
    So, in 'terms of PHP-code', it is in the authentication part the Session gets set up (and probably some sessionvariables get assigned). The authorization part is where we check if a user belong to a certain group or has the right permissions to execute the action, right?
    I just coded basic Filter, Validator and InputController classes that I will post as soon as I write an example using them. I consider an Input Controller to be the front-end of an Application Controller, so hopefully they will be a start.
    Great! Please post your code soon

  9. #309
    SitePoint Guru 33degrees's Avatar
    Join Date
    May 2005
    Posts
    707
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Overunner
    So, in 'terms of PHP-code', it is in the authentication part the Session gets set up (and probably some sessionvariables get assigned). The authorization part is where we check if a user belong to a certain group or has the right permissions to execute the action, right?
    The way I usually work is, in my authorisation code, I call a static method to retrieve the currently logged user, and then call the User object's has_permission method to see if that user is allowed to execute the desired action. This means that authentication and authorisation get done at the same time, which may or may not be the best approach.

  10. #310
    SitePoint Guru
    Join Date
    Oct 2001
    Posts
    656
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    This means that authentication and authorisation get done at the same time, which may or may not be the best approach.
    It doesn't. To "retrieve the currently logged [in] user", like you say, there must already be a "currently logged [in] user", in other words an authenticated user.

    Overunner, yep, you got the idea.

  11. #311
    SitePoint Guru 33degrees's Avatar
    Join Date
    May 2005
    Posts
    707
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Captain Proton
    It doesn't. To "retrieve the currently logged [in] user", like you say, there must already be a "currently logged [in] user", in other words an authenticated user.


    I meant that both happen at the same level of the application; in my case, at the Application Controller level. This is different than doing the authentication at the Front Controller level, which is what other people have suggested.

  12. #312
    SitePoint Guru 33degrees's Avatar
    Join Date
    May 2005
    Posts
    707
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by arborint
    Re: Config class
    That makes sense and it would be good to have examples that use XML, INI and just strait PHP include with an array declared. I think there are actually Readers classes below a Config class. Readers would supply data in a standard way to Config and Mapper classes. Please contribute an XML or INI Reader if you have one and we can use it as a start. There is probably common code between the "Reader" classes. There is also may be common code between the Config and Mapper classes.
    I'd say Reader classes should also do Writing, and would be quite usefull in the Model layer. I currently don't have anything ready to contribute, and I think it would be useful to first decide what the "standard way" would be. Since we're dealing with multi-dimensional data, it would either be as arrays, or as a simple object structure, such as the one returned by the SimpleXML functions. I prefer the latter approach...

    Quote Originally Posted by arborint
    Re: Session Object
    I have been pushing this need back because I don't then the Request is the place for it. I really think that we probably needs some standard implementation of a State/Session data model that we can provide different Data Sources on the backend. It is really just a Model that the Controllers know about as well as the View. If we think of it as being in the Model layer then it will be a cleaner and more flexible implementation.
    I feel a session object should exist at the same level as the request object, although seperate. Something like:

    PHP Code:
    class FrontController
    {
        var 
    $mapper;

        function 
    FrontController(&$mapper) {
            
    $this->mapper =& $mapper;
        }

        function 
    execute(&$request, &$response, &$state) {
            
    $dispatcher =& $this->mapper->mapRequest($request);
            if (
    method_exists($dispatcher'execute')) {
                
    $dispatcher->execute($request$response$state);
            }
        }
    // end class FrontController 

  13. #313
    SitePoint Wizard
    Join Date
    Aug 2004
    Location
    California
    Posts
    1,672
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by 33degrees
    The way I usually work is, in my authorisation code, I call a static method to retrieve the currently logged user, and then call the User object's has_permission method to see if that user is allowed to execute the desired action. This means that authentication and authorisation get done at the same time, which may or may not be the best approach.
    I'm don't think that they should be done at the same time, and I'm not sure you are. I wish we could get rid of the term "authorisation". It is confusing both because is so similar to authentication and because it is the wrong side of what the code we are talking about does. Authorisation sounds like giving someone a potential capablity. Being authorised to do something is not the same as acutually doing it. That's why I prefer the term "Access Control". As examples: RBAC stands for Role Based Access Control and ACL is Access Control List.

    Authentication is determining a person or computer is who they say they are. This is done with a login page with userid/password or by some other means. Once a person or computer is authenticated then you can use the Access Control information on file for them to grant them access. Once authenticated the check does not have done until the session expires or some timeout/logout condition is met.

    Access Control is the check done on some/every request to determine if a person or computer 1) needs to be authenticated (i.e. logged in) to access a "page" or 2) if authenticated has permission to access it.
    Christopher

  14. #314
    SitePoint Wizard
    Join Date
    Aug 2004
    Location
    California
    Posts
    1,672
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I feel a session object should exist at the same level as the request object, although seperate.
    What do people think about a State/Session object?
    Is a global Singleton the best solution or a bad smell?
    If it's a global, would accessing it through a global Locator be a more flexible choice?
    Should it be passed through the controllers like 33degrees shows or provided under certain conditions like a Model object?
    And if all these solutions are stink, do we hold our noses or try something like Dependency Injection?
    Christopher

  15. #315
    simple tester McGruff's Avatar
    Join Date
    Sep 2003
    Location
    Glasgow
    Posts
    1,690
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    A session id is propagated in an http request. I'd see the Request object as responsible for managing the session mechanism, ie starting a session and setting any session data.

  16. #316
    SitePoint Wizard
    Join Date
    Aug 2004
    Location
    California
    Posts
    1,672
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by McGruff
    A session id is propagated in an http request. I'd see the Request object as responsible for managing the session mechanism, ie starting a session and setting any session data.
    I don't agree that because the session id is passed in the request, the code to access the session data should be in the request. By that logic any object that uses a key passed via the request should have it's code in the request as well. I see the session as a data access layer object. Just because $_SESSION looks like $_POST does not mean it is the same kind of thing.

    But I also see the practical sense in stuffing the session into the request. They are used in similar ways and accessed in similar places in the code.

    What do others think?
    Christopher

  17. #317
    SitePoint Guru 33degrees's Avatar
    Join Date
    May 2005
    Posts
    707
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by arborint
    I don't agree that because the session id is passed in the request, the code to access the session data should be in the request. By that logic any object that uses a key passed via the request should have it's code in the request as well. I see the session as a data access layer object. Just because $_SESSION looks like $_POST does not mean it is the same kind of thing.
    One of the main reasons for encapsulating state in an object is that there are many different approaches to maintaining that info; you can use cookies, the built in file based session mechanism, a database, shared memory, etc... each of these implementations should be a seperate class.

    Logically, also, state and request are different concepts, so even though the underlying mechanisms are similar, I think it's more intuitive to keep them seperate.

    As far as implementation goes, the singleton approach works for me, but since the state and the request objects are similar, why not handle them similarly? As for dependancy injection, I'm not really familiar with it, I'd be curious to know how that would work in this context.

  18. #318
    SitePoint Zealot Overunner's Avatar
    Join Date
    Mar 2004
    Location
    Sweden
    Posts
    180
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    So we can all agree on that authorization should be done at FC level (in the HandlerChain more specifically), and Access Control in each individual action?
    Quote Originally Posted by arborint
    I have been pushing this need back because I don't then the Request is the place for it. I really think that we probably needs some standard implementation of a State/Session data model that we can provide different Data Sources on the backend. It is really just a Model that the Controllers know about as well as the View. If we think of it as being in the Model layer then it will be a cleaner and more flexible implementation.
    Again, I'm not 100% on all the terminology, but let's see if I understand what you mean. By Data Source, do you mean the different Data Source patterns (Table Data Gateway, Row Data Gateway, Active Record, Data Mapper) or just different formats for the persistent data (flat files, XML, database).
    And the "State/Session data model" would then act as a...Dependency Injector? E.g
    PHP Code:
    $depenencyInjector DepenencyInjector :: getInstance();
    $depenencyInjector->register('TableDataGateway');
    // ...
    $tdg depenencyInjector->create('TableDataGateway'); 
    (sorry to bother you with these noobish questions, but i have to learn this ****)

  19. #319
    SitePoint Guru
    Join Date
    Oct 2001
    Posts
    656
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    So we can all agree on that authorization should be done at FC level (in the HandlerChain more specifically), and Access Control in each individual action?
    Eh, no. You probably mean the reverse.

    But even then, the way arborint defines access control implies that it also involves the step of checking for valid authentication credentials (for example, not the login form, but the checking for a valid cookie). I think that should really be done at the FC level and I also think it is a part of the authentication process.

    Here's how I would define the two:

    Authentication is determining a person or computer is who they say they are. This is done with a login page with userid/password or by some other means. Once a person or computer is authenticated then you can use the Access Control information on file for them to grant them access. Once authenticated the check does not have done until the session expires or some timeout/logout condition is met.

    Authorization is the check done on some/every request to determine if a person or computer has permission to access it.

  20. #320
    SitePoint Wizard
    Join Date
    Aug 2004
    Location
    California
    Posts
    1,672
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Captain Proton
    Eh, no. You probably mean the reverse.
    I agree with the Captain that is usually the reverse. And I believe from the definitions that He uses Authorization to mean Access Control.

    Quote Originally Posted by Captain Proton
    But even then, the way arborint defines access control implies that it also involves the step of checking for valid authentication credentials (for example, not the login form, but the checking for a valid cookie). I think that should really be done at the FC level and I also think it is a part of the authentication process.
    No, I definitely don't think that there should be any checking of authentication credentials when doing Access Control. The Access Control check may forward the user to an Authentication (login) page if the access check fails.

    Where we differ is that the Captain thinks that Access Control should be done in the FC, I think it can be done in the FC, but also in the AC as well. To do Access Control in the FC usually requires a map containing the Access Control information. In PHP it is often easier to put the Access Control into the code of the AC rather than have a map. This is an area where Dependency Injection would bridge the gap by allowing both with the same call,
    Christopher

  21. #321
    SitePoint Zealot Overunner's Avatar
    Join Date
    Mar 2004
    Location
    Sweden
    Posts
    180
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by arborint
    I agree with the Captain that is usually the reverse. And I believe from the definitions that He uses Authorization to mean Access Control.
    You're right, I mixed up the terms...
    Where we differ is that the Captain thinks that Access Control should be done in the FC, I think it can be done in the FC, but also in the AC as well. To do Access Control in the FC usually requires a map containing the Access Control information. In PHP it is often easier to put the Access Control into the code of the AC rather than have a map. This is an area where Dependency Injection would bridge the gap by allowing both with the same call.
    Since not every request (actually very few?) requires some kind of a map to be dispatched, the Access Control should reside in the Application Controller. Otherwise the map will only contain access control information, no?

  22. #322
    SitePoint Wizard
    Join Date
    Aug 2004
    Location
    California
    Posts
    1,672
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Overunner
    Since not every request (actually very few?) requires some kind of a map to be dispatched, the Access Control should reside in the Application Controller. Otherwise the map will only contain access control information, no?
    This is why we want to be able to support both, because it depends on the type of site and the programmers preference.

    Many websites have mostly pages that require no Access Control. In these cases there are small areas of the site, such as admin pages or checkout, that require the user to have been Authenticated. However there are classes of websites, intranets are a good example, where all pages have Access Control and different areas require different permissions. I should note that the complexity of the Access Control does not directly relate to its location in the code, so you could have a full RBAC system or just an "is logged in" check using either scheme.

    Also some programmers prefer, and some designs dictate, a central Access Control Map that allows you to specify access for all pages. The skeleton ActionLookupMapper has a place for data that can be used for this because it makes sense to associate access with actions, not code. And by putting everything in one map you require only one load for all your data. Ultimately we need some predefined points where Access Control code can be inserted to do the check and be able to change the current action on failure.
    Christopher

  23. #323
    SitePoint Wizard
    Join Date
    Aug 2004
    Location
    California
    Posts
    1,672
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I thought I would post some code to see if we could move toward an Application controller to put behind the skeleton Front Controller. Like the Front Controller code, I think the Application Controller should be a bunch of little classes that work together to make the whole. I know kyberfabrikken is a fan of small classes (probably more than I am ) and I think the Front Controller shows that it is a good goal for classes.

    Because an Application Controller is much more complicated than the Front Controller I think it should be done in pieces that communicate with each other with clean interfaces. This is for a couple of reasons: smaller pieces are easier to test and not everyone needs the whole Application Controller so the parts should be useful.

    The code below is an example of what I will call an Input Controller. I consider something like this to be the front-end request processor for any controller., So the Input Controller might also be inherited by other special purpose controllers like a Form Controller, Pager/List Controller, Upload/Download Controller, etc.

    All I want the Input Controller to do is filter and validate the Request parameters I am interested in and then let me know if there were any problems. Filtering and validating the request is usuallly at the top of lists of most important best practices for PHP programmers

    I used general purpose Filter and Validator classes and then have the Input Controller manage things. Here is the code:

    Filter class:
    PHP Code:
    class Filter {
    var 
    $chain = array();

    function 
    addFilter (&$filter) {
        if (
    is_array($filter)) {
            
    $this->chain array_merge($this->chain$filter);
        } else {
            
    $this->chain[] = $filter;
        }
    }
        
    function 
    doFilter ($value$filter=null) {
        if (
    $filter) {
            
    $this->chain $filter;
        }
        foreach (
    $this->chain as $filter) {
            
    $value $filter->doFilter($value);
        }
        return (
    $value);
    }
        
    // end class Filter 
    Validator class:
    PHP Code:
    class Validator {
    var 
    $chain = array();
    var 
    $errmsg = array();
    var 
    $error 0;

    function 
    addRule(&$rule) {
        if (
    is_array($rule)) {
            
    $this->chain array_merge($this->chain$rule);
        } else {
            
    $this->chain[] = $rule;
        }
    }
        
    function 
    validate ($value$rule=null)
    {
        if (
    $rule) {
            
    $this->chain $rule;
        }
        
    $this->errmsg = array();
        
    $this->error 0;
        foreach (
    $this->chain as $rule) {
            if (! 
    $rule->check($value)) {
                
    $this->errmsg[$this->error] = $rule->getMessage();
            }
                ++
    $this->error;
        }
        return 
    $this->error;
    }

    function 
    isError ()
    {
        return 
    $this->error;
    }

    function 
    getMessage ()
    {
        if (
    $this->error) {
            return 
    $this->errmsg;
        }
        return 
    '';
    }

    // end class Validator 
    Input Controller class:
    PHP Code:
    class InputController {
    var 
    $params = array();
    var 
    $error false;

    function 
    InputController() {
    }

    function 
    addParameter($name, &$object) {
        if (
    $name && $object) {
            
    $this->params[$name] =& $object;
        }
    }

    function & 
    getParameter($name) {
        if (! isset(
    $this->params[$name])) {
            
    $this->addParameter($name, new InputControllerParameter($name));
        }
        return 
    $this->params[$name];
    }

    function 
    processRequest($request) {

        
    $filter =& new Filter();
        
    $validator =& new Validator();

        
    $this->errmsg = array();
        
    $this->error false;
        foreach (
    $this->params as $key => $param) {
            
    $this->params[$key]->value $filter->doFilter($request->get($param->name), $param->filters);
            
    $validator->validate($this->params[$key]->value$param->rules);
            if (
    $validator->isError()) {
                
    $this->params[$key]->errmsg $validator->getMessage();
                
    $this->error true;
            } else {
                
    $this->params[$key]->errmsg = array();
            }
        }
        
        return ! 
    $this->error;
    }

    function 
    isError() {
        return 
    $this->error;
    }

    function 
    getMessage() {
        
    $errmsg = array();
        if (
    $this->error) {
            foreach (
    $this->params as $key => $param) {
                if (
    $param->errmsg) {
                    
    $errmsg[$key] = $param->errmsg;
                }
            }
        }
        return 
    $errmsg;
    }

    // end class InputController 
    It would be used like this:
    PHP Code:
    $controller =& new InputController();

    $param1 =& $controller->getParameter('field1');
    $param1->addFilter(new MyFilter());
    $param1->addRule(new MyValidator('Error message for Field 1'));

    $controller->processRequest(new Request());
    if (
    $controller->isError()) {
        
    $error_msg_array $controller->getMessage();

    This is pretty minimal code (e.g. no way to clear any of the chains, get values from the controller, etc. etc.).

    A full set of code with an example, rules, filters and unit tests is here:
    Input Controller example

    For those who have lost track there is a CVS snapshot of the skeleton Front Controller here:
    Skeleton Front Controller
    Christopher

  24. #324
    SitePoint Guru
    Join Date
    May 2005
    Location
    Finland
    Posts
    608
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Very interesting by the looks of it, arborint. I'll have to get back to you on that later.

    (How about writing experimental code in PHP5 to be as concise and precise as possible? Interfaces and type hinting make it easier to see what relates to what and what's actually going on at procedural level.)

  25. #325
    SitePoint Wizard
    Join Date
    Aug 2004
    Location
    California
    Posts
    1,672
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Ezku
    (How about writing experimental code in PHP5 to be as concise and precise as possible? Interfaces and type hinting make it easier to see what relates to what and what's actually going on at procedural level.)
    I have been pushing for everything in PHP4 so everyone could try the code. Plus I think things like interfaces are confusing extras to programmers new to these concepts (which is how the thread started). If we actually create a full skeleton application, then a PHP5 version with interfaces and type hinting (and without all the object referencing) would be an excellent idea. But there will be refactoring backwards as we move forwards so it doesn't make sense to maintain both PHP4 and PHP5 versions for now.

    PS - I am making a mental note that Ezku volunteered to work on the PHP5 version
    Christopher


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
  •