Dependency Injection(DI),
              Phemto
                  Романичев Владимир

VETMANAGER TEAM        26.4.12   Стр. 1
VETMANAGER TEAM   26.4.12   Стр. 2
План
  1)Как плохо без Dependency Injection
  2)Как хорошо с Dependency Injection
  3)Как плохо с Dependency Injection
  4)Как хорошо с Phemto
  5)Как хорошо :)




VETMANAGER TEAM          26.4.12   Стр. 3
Как плохо
 class Stores {
  function add($data){
     $query = 'INSERT INTO stores SET title=?
        , assigned_user_id=?, type=?';
     NDatabase::query($query, array($data['title']
        , $data['assigned_user_id'], $data['type_id']));
  }


Stores::add

VETMANAGER TEAM                 26.4.12   Стр. 4
Как плохо

    Как тестировать?(никак)

    Как работать с несколькими коннектами? (никак)

    Как подменить СУБД?(кое-как)

    Как использовать в другом проекте?(кое-как)

    Как перейти на NoSQL?(никак)




VETMANAGER TEAM             26.4.12   Стр. 5
Делаем инъекцию
class Stores{
   public function __construct($database) {
   }
   function add($data){
     $query = 'INSERT INTO stores SET title=?
             , assigned_user_id=?, type=?';
     $this->_database
             ->query($query, $data);
   }

VETMANAGER TEAM          26.4.12   Стр. 6
Лучше

    Как тестировать?(легко)

    Как работать с несколькими коннектами? (легко)

    Как подменить СУБД?(легче)

    Как использовать в другом проекте?(легче)

    Как перейти на NoSQL?(никак)




VETMANAGER TEAM             26.4.12   Стр. 7
Пишем тест...
              class StoresTest extends
                        PHPUnit_Framework_TestCase
              {
                 function setUp(){
                   $this->dbMock = $this
                              ->getMock('VMDatabase');
                   $this->testObject =
                                   new Stores($this->dbMock
                 }


VETMANAGER TEAM                  26.4.12   Стр. 8
Пишем тест...
            function testAdd(){
              $this->dbMock->expects($this->once())
                    ->method('query')
                    ->with(
                       $this->stringContains("INSERT")
                       , $this->equalTo(array('title', 1, 2))
                    );
              $this->testObject->add($testData);
            }



VETMANAGER TEAM                   26.4.12   Стр. 9
Как плохо с DI
             $stores = new Stores(new VMDatabase());
                  $stores = new Stores(
                      new VMDatabase()
                     , new VMRequest()
                     , new VMSession()
                     , new UserModel()
                     …
                  );


VETMANAGER TEAM                  26.4.12   Стр. 10
Как хорошо с Phemto
public function __construct(VMDatabase $database) {
  $this->_database = $database;
}


require_once 'phemto/phemto.php';
$injector = new Phemto();
$stores = $injector->create('Stores');




VETMANAGER TEAM              26.4.12     Стр. 11
Как хорошо с Phemto2
      public function __construct($database) {
        $this->_database = $database;
      }

   require_once 'phemto/phemto.php';
   $injector = new Phemto();
   $injector->forVariable('database')
         ->willUse(new Reused('VMDatabase'));

   $stores = $injector->create('Stores');


VETMANAGER TEAM               26.4.12   Стр. 12
Лучше

    Как тестировать?(легко)

    Как работать с несколькими коннектами? (легко)

    Как подменить СУБД?(легче)

    Как использовать в другом проекте?(легче)

    Как перейти на NoSQL?(никак)




VETMANAGER TEAM             26.4.12   Стр. 13
ActiveRecord
  class Stores {
     function dataWrap($data){...}
     protected function getEntity(){...}
     function add($data){
       $entity = $this->getEntity();
       $entity->import($this->dataWrap($data));
       $entity->save();
     }



VETMANAGER TEAM              26.4.12   Стр. 14
Лучше?(getEntity)

    Как тестировать?(???)

    Как работать с несколькими коннектами?(???)

    Как подменить СУБД?(легко)

    Как использовать в другом проекте?(???)

    Как перейти на NoSQL?(легко)




VETMANAGER TEAM             26.4.12   Стр. 15
Стальной getEntity
            protected function getEntity(){
              $entity = new StoresRow();
              return $entity;
            }




VETMANAGER TEAM               26.4.12   Стр. 16
Фабричный getEntity
  protected function getEntity(){
    return $this->factory->create('StoresRow');
  }

Тест
$ourMock = $this->getMock('StoresRow');
$factoryMock = $this->expects($this->once())
     ->method('create')
     ->will($this->returnValue($ourMock))

  VETMANAGER TEAM           26.4.12   Стр. 17
getEntity
            protected function getEntity(){
              return $this->_entity;
            }




VETMANAGER TEAM               26.4.12   Стр. 18
Новый Stores
   class Stores {
      public function __construct($entity) {
        $this->_entity = $entity;
      }


   $injector->whenCreating('Stores')
     ->forVariable('entity')
     ->willUse('StoresRow');

VETMANAGER TEAM             26.4.12   Стр. 19
Новый тест Stores
$this->entityMock->expects($this->once())
        ->method('import')
        ->with($this->equalTo($needParam));

$this->entityMock->expects($this->once())
        ->method('save');

$this->testObject->add($testData);



VETMANAGER TEAM           26.4.12    Стр. 20
Наш ActiveRecord
 class StoresRow extends Entity {
    protected $_fields = array ();
    protected $_table = 'stores';
    public function __construct($database) {
      $this->setDB($database);
    }




VETMANAGER TEAM             26.4.12   Стр. 21
Тест ActiveRecord
function testSaveWithoutId(){
  $this->dbMock->expects($this->once())
        ->method('query')
        ->with($this->stringContains("INSERT"));
  $this->testObject->import($testData);
  $this->testObject->save();
}




  VETMANAGER TEAM              26.4.12   Стр. 22
Phemto итог
    #wiring.php
    require_once 'phemto/phemto.php';
    $injector = new Phemto();
    $injector->forVariable('database')
    ->willUse(new Reused('VMDatabase'));
    $injector->whenCreating('Stores')
    ->forVariable('entity')->willUse('StoresRow');
    return $injector;
    #ajax_store.php
    $injector = include 'wiring.php';
    $stores = $injector->create('Stores');

VETMANAGER TEAM                26.4.12   Стр. 23
Лучше

    Как тестировать?(легко)

    Как работать с несколькими коннектами? (легко)

    Как подменить СУБД?(легко)

    Как использовать в другом проекте?(легко)

    Как перейти на NoSQL?(легко)




VETMANAGER TEAM             26.4.12   Стр. 24
Лучше




VETMANAGER TEAM           26.4.12   Стр. 25
Спасибо за внимание!




VETMANAGER TEAM       26.4.12   Стр. 26

Dependency injection, phemto

  • 1.
    Dependency Injection(DI), Phemto Романичев Владимир VETMANAGER TEAM 26.4.12 Стр. 1
  • 2.
    VETMANAGER TEAM 26.4.12 Стр. 2
  • 3.
    План 1)Какплохо без Dependency Injection 2)Как хорошо с Dependency Injection 3)Как плохо с Dependency Injection 4)Как хорошо с Phemto 5)Как хорошо :) VETMANAGER TEAM 26.4.12 Стр. 3
  • 4.
    Как плохо classStores { function add($data){ $query = 'INSERT INTO stores SET title=? , assigned_user_id=?, type=?'; NDatabase::query($query, array($data['title'] , $data['assigned_user_id'], $data['type_id'])); } Stores::add VETMANAGER TEAM 26.4.12 Стр. 4
  • 5.
    Как плохо  Как тестировать?(никак)  Как работать с несколькими коннектами? (никак)  Как подменить СУБД?(кое-как)  Как использовать в другом проекте?(кое-как)  Как перейти на NoSQL?(никак) VETMANAGER TEAM 26.4.12 Стр. 5
  • 6.
    Делаем инъекцию class Stores{ public function __construct($database) { } function add($data){ $query = 'INSERT INTO stores SET title=? , assigned_user_id=?, type=?'; $this->_database ->query($query, $data); } VETMANAGER TEAM 26.4.12 Стр. 6
  • 7.
    Лучше  Как тестировать?(легко)  Как работать с несколькими коннектами? (легко)  Как подменить СУБД?(легче)  Как использовать в другом проекте?(легче)  Как перейти на NoSQL?(никак) VETMANAGER TEAM 26.4.12 Стр. 7
  • 8.
    Пишем тест... class StoresTest extends PHPUnit_Framework_TestCase { function setUp(){ $this->dbMock = $this ->getMock('VMDatabase'); $this->testObject = new Stores($this->dbMock } VETMANAGER TEAM 26.4.12 Стр. 8
  • 9.
    Пишем тест... function testAdd(){ $this->dbMock->expects($this->once()) ->method('query') ->with( $this->stringContains("INSERT") , $this->equalTo(array('title', 1, 2)) ); $this->testObject->add($testData); } VETMANAGER TEAM 26.4.12 Стр. 9
  • 10.
    Как плохо сDI $stores = new Stores(new VMDatabase()); $stores = new Stores( new VMDatabase() , new VMRequest() , new VMSession() , new UserModel() … ); VETMANAGER TEAM 26.4.12 Стр. 10
  • 11.
    Как хорошо сPhemto public function __construct(VMDatabase $database) { $this->_database = $database; } require_once 'phemto/phemto.php'; $injector = new Phemto(); $stores = $injector->create('Stores'); VETMANAGER TEAM 26.4.12 Стр. 11
  • 12.
    Как хорошо сPhemto2 public function __construct($database) { $this->_database = $database; } require_once 'phemto/phemto.php'; $injector = new Phemto(); $injector->forVariable('database') ->willUse(new Reused('VMDatabase')); $stores = $injector->create('Stores'); VETMANAGER TEAM 26.4.12 Стр. 12
  • 13.
    Лучше  Как тестировать?(легко)  Как работать с несколькими коннектами? (легко)  Как подменить СУБД?(легче)  Как использовать в другом проекте?(легче)  Как перейти на NoSQL?(никак) VETMANAGER TEAM 26.4.12 Стр. 13
  • 14.
    ActiveRecord classStores { function dataWrap($data){...} protected function getEntity(){...} function add($data){ $entity = $this->getEntity(); $entity->import($this->dataWrap($data)); $entity->save(); } VETMANAGER TEAM 26.4.12 Стр. 14
  • 15.
    Лучше?(getEntity)  Как тестировать?(???)  Как работать с несколькими коннектами?(???)  Как подменить СУБД?(легко)  Как использовать в другом проекте?(???)  Как перейти на NoSQL?(легко) VETMANAGER TEAM 26.4.12 Стр. 15
  • 16.
    Стальной getEntity protected function getEntity(){ $entity = new StoresRow(); return $entity; } VETMANAGER TEAM 26.4.12 Стр. 16
  • 17.
    Фабричный getEntity protected function getEntity(){ return $this->factory->create('StoresRow'); } Тест $ourMock = $this->getMock('StoresRow'); $factoryMock = $this->expects($this->once()) ->method('create') ->will($this->returnValue($ourMock)) VETMANAGER TEAM 26.4.12 Стр. 17
  • 18.
    getEntity protected function getEntity(){ return $this->_entity; } VETMANAGER TEAM 26.4.12 Стр. 18
  • 19.
    Новый Stores class Stores { public function __construct($entity) { $this->_entity = $entity; } $injector->whenCreating('Stores') ->forVariable('entity') ->willUse('StoresRow'); VETMANAGER TEAM 26.4.12 Стр. 19
  • 20.
    Новый тест Stores $this->entityMock->expects($this->once()) ->method('import') ->with($this->equalTo($needParam)); $this->entityMock->expects($this->once()) ->method('save'); $this->testObject->add($testData); VETMANAGER TEAM 26.4.12 Стр. 20
  • 21.
    Наш ActiveRecord classStoresRow extends Entity { protected $_fields = array (); protected $_table = 'stores'; public function __construct($database) { $this->setDB($database); } VETMANAGER TEAM 26.4.12 Стр. 21
  • 22.
    Тест ActiveRecord function testSaveWithoutId(){ $this->dbMock->expects($this->once()) ->method('query') ->with($this->stringContains("INSERT")); $this->testObject->import($testData); $this->testObject->save(); } VETMANAGER TEAM 26.4.12 Стр. 22
  • 23.
    Phemto итог #wiring.php require_once 'phemto/phemto.php'; $injector = new Phemto(); $injector->forVariable('database') ->willUse(new Reused('VMDatabase')); $injector->whenCreating('Stores') ->forVariable('entity')->willUse('StoresRow'); return $injector; #ajax_store.php $injector = include 'wiring.php'; $stores = $injector->create('Stores'); VETMANAGER TEAM 26.4.12 Стр. 23
  • 24.
    Лучше  Как тестировать?(легко)  Как работать с несколькими коннектами? (легко)  Как подменить СУБД?(легко)  Как использовать в другом проекте?(легко)  Как перейти на NoSQL?(легко) VETMANAGER TEAM 26.4.12 Стр. 24
  • 25.
    Лучше VETMANAGER TEAM 26.4.12 Стр. 25
  • 26.