SitePoint Sponsor

User Tag List

Results 1 to 10 of 10

Threaded View

  1. #1
    SitePoint Addict
    Join Date
    Jul 2014
    Posts
    236
    Mentioned
    1 Post(s)
    Tagged
    0 Thread(s)

    [PHP] Creating a "portable" database connection / dependency injection container

    I see a lot of requests for help involving MySQL where database connections are created manually each time the DB needs accessed, whether it be inside a class or function, or just a "loose" file...also see a lot of require("connection.php")
    stuff as well.

    Thought I'd help out and show one method of creating a portable database connection, implementing PDO as the interface. Note, there are many ways to do this, but most of those ways involve doing crazy and/or questionable things (global variables, singletons, etc ).
    The method I'm about to introduce avoids any "code smell", and ensures that you can access your DB from any scope, anywhere, by simply setting the connection details one time, and importing it directly whenever needed.
    Shameless plug -- this is taken from a PHP framework that I am working on, located at https://github.com/arout/kwfusion

    Not only that, but at the end of this post, I will show you how to use this registry to make practically anything portable, not just your database. This registry application also acts as a dependency injector, so that you can ensure that every module you use has all of it's dependencies met before you use it!

    Before you get started, this will require that you have PHP version 5.3 or newer ( which is no problem, since you are using ver 5.5+ anyway, right? Right?? )

    Let's get to work:

    First, create a file called registry.php.

    Inside registry.php, insert the following code:

    PHP Code:
    class Application {

        protected static 
    $registry = array();
     
        
    /**
         * Add a new resolver to the registry array.
         * @param  string $name The id
         * @param  object $resolve Closure that creates instance
         * @return void
         */
        
    public static function register($nameClosure $resolve) {
            
            static::
    $registry[$name] = $resolve;
        }
     
        
    /**
         * Create the instance
         * @param  string $name The id
         * @return mixed
         */
        
    public static function run($name) {
            
            if ( static::
    registered($name) ) {
                
                
    $name = static::$registry[$name];
                return 
    $name();
            }
     
            throw new 
    Exception($name' not found');
        }
     
        
    /**
         * Determine whether the id is registered
         * @param  string $name The id
         * @return bool Whether to id exists or not
         */
        
    public static function registered($name) {
            
            return 
    array_key_exists($name, static::$registry);
        }

    The purpose of this file (registry.php) :

    As the file name suggests, this will act as a registry -- it will check if you have already registered a module (your database) and will throw an exception if you have not yet registered the requested model. You will only need to register a module one time.

    Next, in the same directory as registry.php, create a file named db.php. Include the following in db.php:

    PHP Code:
    <?php
    namespace Your\Namespace;
    use \
    PDO as PDO;

    ##########################################
    // Add `Database` to the registry array
    ##########################################

    if( ! class_exists("Application") ) require( dirname(__FILE__).'registry.php' );

    \
    Application::register'Database', function() {
        

    ## Enter your database connection settings here

    $host         "localhost";            // Most users should leave this set to localhost
    $sqlname  " ";                            // Name of database
    $sql_user  " ";                    // Username to connect to database
    $sql_pass " ";                        // Database password
            
    ## Setup PDO connection
    try {  
            
    $sql = new PDO("mysql:host=$host;dbname=$sqlname"$sql_user$sql_pass); 
            
    $sql->setAttributePDO::ATTR_EMULATE_PREPARESfalse ); 
            
    $sql->setAttributePDO::ATTR_ERRMODEPDO::ERRMODE_EXCEPTION );
    }  
    catch(
    PDOException $e) {  
            echo 
    '<h1>Fatal Error</h1>
            Could not establish connection to the database. '
    ;  
            
    file_put_contents('PDO_errors.txt'$e->getMessage(), FILE_APPEND);  
    }

        return 
    $sql;
    });
    Make sure to edit the namespace, as well as entering your DB settings.

    How to use:

    Importing the file
    Ideally, you already have Composer or some other method for autoloading files, in which case this will "just work" after you let your autoloader know where to find these files....otherwise, simply include the db.php file when you need to get to the database.

    Working with the database
    This is where this script earns it's bacon. Regardless of whether you are inside a class, function, other side of Jupiter, you need not worry about passing dependencies or anything else to get to your database. Simply call it like this:

    PHP Code:
    \Application::run('Database'); 
    More specifically, here is a working example of how to do it:

    PHP Code:
     // Store the connection as $db
     
    $db = \Application::run('Database');

     
    // Now just use it like any other PDO connection
     
    $query " SELECT something FROM some_table WHERE data = ? ";
     
    $result $db->prepare($q);
     
    $result->execute( array( $_POST['blah'] ) );

     foreach(
    $result as $row)
         echo 
    $row['blahblah']; 
    That's all there is to it.


    Adding module to the registry

    To add other modules to the registry, you simply:

    PHP Code:
    ###############################################
    // Add your custom router to the registry array
    ###############################################
    Application::register'Router', function() {
        
        return new 
    Your\Namespace\Router;
    }); 
    Give your module a name as the first argument ( in this case, I named my router....Router ).
    The line: return new Your\Namespace\Router; is simply instantiating the Router class that you would have created elsewhere.

    Then use it like you did the database:

    PHP Code:
     $router = \Application::run('Router'); 
    This in itself is not very useful if you already have autoloading set up....you can just as easily simply instantiate your class as normal. To recieve it's true value, we would use this as a dependency injection container.
    Here is an example of it injecting dependencies ( copy/pasted from my framework ):

    PHP Code:
    ###################################################
    // Add `System Controller` to the registry array //
    ###################################################
    Application::register'SystemController', function() {
        
        
    // Give the System Controller access to:
        // database, config, router, system model, system view
        
    $config    Application::run('Config');
        
    $route     Application::run('Router');
        
    $model     Application::run('SystemModel');
        
    $view     Application::run('SystemView');

        
    $sys_controller = new Fusion\System\SystemController$config$route$model$view );

        
    $sys_controller->dispatch();

        return 
    $sys_controller;
    }); 
    Feel free to ask any questions if you need help. Enjoy!
    Last edited by arout77; Jul 30, 2014 at 20:19. Reason: Formatting sucks


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
  •