Writing Your Framework

    PHP Frameworks
    For beginners, "cyclists" or just curious ...



    This article is not a call to action, but only a small sketch on the topic "How would I do it." At the moment, I have actively used the Zend Framework in my department, and I’m best acquainted with it, so don’t be afraid of parallels, this is not an advertisement, because most frameworks equally combine pros and cons, and we only need advantages ...

    rules


    I would start by setting the rules:
    • Coding standards - it’s better to use existing ones, I advise Zend Framework’s standards
    • The process of adding code to the repository (even if you yourself are in the project - this will discipline well), just do not go too far, otherwise it will slow down the development of the project

    Without developing these rules, you risk turning the framework into a garbage dump. Also, I highly recommend writing unit tests - they will save a lot of time.

    Architecture


    I hope most readers are already familiar with the MVC ( Model-View-Controller ) pattern - so let's base our framework on it, using something else, I'm afraid it will scare away users (here I mean programmers :)).

    Model


    In a typical project, the model is tied to one table in the database, but there are enough exceptions, so this statement should not be taken as an axiom. Our model should easily work with various data storages, whether it be databases, files, or memory.

    Let's imagine what a model might look like:

    // the User model uses the Model
    Model_User extends Framework_Model_Database
    {
        $ _table = "users";
        $ _pkey = "id";
     
        function getByLogin ($ login) {/*...*/}
        function getByEmail ($ email) {/*...*/}
    }
     
    // The MainConfig model uses the
    class Model_MainConfig extends Framework_Model_Ini
    {
        protected $ _file = "application.ini";
     
        function setOption ($ key) {/*...*/}
        function getOption ($ key) {/*...*/}
    }
     
    // the registry model uses memory as a storage - an alternative to the global variables
    class Model_Registry extends Framework_Model_Memory
    {
        function setOption ($ key) {/*...*/}
        function getOption ($ key) {/*...*/}
    }
     
    // the Session model uses session files as a storage
    class Model_Session extends Framework_Model_Session
    {
        protected $ _namespace = "global";
     
        function setOption ($ key) {/*...*/}
        function getOption ($ key) {/*...*/}
    }


    In fact, with such examples, I strongly distort the idea of ​​MVC - because often a model means a certain business model, but not a session or a configuration file.


    View


    What are the requirements for the template engine now? For me personally, native PHP syntax, support for various kinds of helpers and filters. The “Two Step View pattern” should also be implemented, in ZF there are two components for this - Zend_View and Zend_Layout .

    I will give an example of such a representation:
    books):?>         books as $ key => $ val):?>
        
        
            
                
                
            

            
                
                
            
            
        
    AuthorTitle
    escape ($ val ['author'])?>escape ($ val ['title'])?>


        

    There are no books to display.



    An example of using layouts (taken from the Zend_Layout documentation):

    Layout Example

    Oh yes, the Zend Framework has a successful implementation of the presentation, I like it, of course, not without minor complaints, but in general it’s five.


    Controller


    The controller must fulfill its duties - to process the request, kick the model and presentation - so that the user gets the desired result.

    Let's try to respond to a user request of the following form: example.com/?controller=users&action=profile&id=16

    So, let's analyze it - we are asked to show a user profile with id = 16. Accordingly, the existence of a users controller with the profile method, which could get some id as a parameter, suggests itself:
    // controller name must contain a prefix - so as not to confuse
    class Controller_Users extends Framework_Controller_Action
    {
        public function actionProfile ()
        {
            // get data from the request
            $ id = $ this-> request-> get ('id');
     
            // kick the model
            $ user = new Model_User ();
            $ user -> getById ($ id);
     
            // throw data into the view
            $ this-> view-> user = $ user;
        }
    }


    Naturally, the controller also has the obligation to change the presentation format, i.e. if we need to return data in JSON format, then there should be no other conclusion (this is already implied by MVC itself, but it’s worth recalling once again).

    Whoever more closely sees in this example the appearance of a certain Request'a is an object that parses an incoming request. Why is it needed - more on that later.


    Routers


    Now a little about the requirements from end users - in particular about CNC . Compare the following link options: Routers are used to generate / parse such an incoming request in ZF - in fact, these are the rules for constructing URLs, we will also have to implement them - and this is hard to argue with.

    example.com/?controller=users&action=profile&id=16
    example.com/users/profile/id/16 // стандартная схема построения URL'a в ZF
    example.com/users/profile/16 // CodeIgniter
    example.com/profile/16 // возможное пожелание заказчика, и его нужно выполнять




    I prefer passing named parameters - this URL is easier to read, compare:
    example.com/users/list/page/2/limit/20/filter/active
    and
    example.com/users/list/2/20/active


    You probably want to immediately put this functionality directly into the Request class, but do not rush, because we still need to generate the correct URLs in the View - and calling the Request object there is a little logical, let's leave this to the conscience of a separate class, which can be accessed as Request and View


    Request & Response


    With the purpose of the Request class, I think there are no problems - not so many are included in its functions:
    • processing incoming parameters with all the rules from the Router
    • send parameters to the controller on demand

    But there is also Response - I didn’t mention it before, what should it do:
    • form a response header
    • form an answer - i.e. take view, wrap in a certain layout and exit

    I don't really like the Response implementation in ZF - there is too much extra in it


    Modules


    The framework must be modular, i.e. by writing a module (blog, forum, etc.) you can easily use this code in other applications. To do this, we only need to separate the MVC of each module into its own directory, while some module will remain behind the main one.

    Core


    Now it’s worth moving on to the tastiest thing - directly to the core of the system, we’ve already described its functionality, you just have to draw a line:

    1. Upon initialization, the incoming request must be processed by all the Router rules, so that the Request object can return the requested value to us by key
    2. The Request object must also know which module / controller / action is being requested
    3. The kernel should load the necessary controller and call the requested action (controller method)
    4. After testing the controller, Response is called and puts an end to

    For flexibility, you should add either hooks or plugins to each of the listed stages.

    Helper classes


    If you want to practice writing “bikes,” you can start from here:

    • Working with the database - you need support for MySQL, SQLite, PostgreSQL (this is the minimum), but in general it is worth paying a lot of attention to this item, because he alone can attract many users
    • Validators are a necessary thing to save time when writing forms (see Zend_Validate )
    • Translator - to implement multilanguage in the system, gettext is probably enough, but you should not hope for it
    • Mail - you can do only the mail function, but it’s somehow not like an adult
    • Paginator - for solving a trivial task - pagination (see Zend_Paginator )
    • Navigator - building menus, sitemaps and breadcrumbs (see Zend_Navigation )
    • Caching - nowhere without it (see Zend_Cache )
    • Configuration files - Zend_Config is too large to process only one ini file, you can practice here, but still look at Zend_Config_Ini
    • Autoloader is a very useful thing, and most importantly convenient - Zend_Loader
    • ACL - it may be required - at least, the distribution of rights on request module / controller / action is better if it is wired in the system

    It is not by chance that I provide links to Zend Framewrok's packages - they are quite adequate and independent, can be used on their own, i.e. after all, nobody waves you to build your framework from Zend’s cubes (and here's an example: ZYM )


    Trivial tasks


    The framework should contain functionality for solving the following trivial tasks (small and not so):

    • Redirect - the most common, called from the controller
    • Forward is forwarding from one module / controller / action to another without reloading the page
    • Messages - various messages, with the possibility of receiving them after reloading the page
    • Scaffold - a quick way to build an application for editing records in a database (exaggerated)


    Even better, if the framework will be delivered ready to use CMS system - it will help to popularize your brainchild, and possibly attract third-party developers.

    Perhaps what I forgot from the "trivial" - write ...


    Directory structure


    And so, what we get if you look at the file system (only the public folder should be in document_root):
    project
    | - application
    | | - configs
    | | - layouts
    | | - controllers
    | | - models
    | | - views
    | `- modules
    | `-
    | | - layouts
    | | - controllers
    | | - models
    | `- views
    | - data
    | | - cache
    | | - logs
    | `- sessions
    | - library
    | `- Framework
    | - public
    | | - styles
    | | - scripts
    | | - images
    | | - uploads
    | | - .htaccess
    | `- index.php
    `- tests
    


    This is only my wish, what kind of a girl it will be for you - you decide ...

    Conclusion


    To Be Or Not To Be - you decide, as for me - you can put up with the shortcomings of a single framework, and enjoy its advantages. Perhaps you try to write your decision or cross existing ones, but don’t forget - writing this kind of application entails the responsibility to support it.

    My blog’s RSS is available at http://anton.shevchuk.name/feed/ , and twitter is here http://twitter.com/AntonShevchuk

    Also popular now: