artur-graniszewski/pdo-proxy

View on GitHub
README.md

Summary

Maintainability
Test Coverage
[![Latest Stable Version](https://poser.pugx.org/pdo-proxy/pdo-proxy/v/stable)](https://packagist.org/packages/pdo-proxy/pdo-proxy) [![Build Status](https://travis-ci.org/artur-graniszewski/pdo-proxy.svg?branch=master)](https://travis-ci.org/artur-graniszewski/pdo-proxy) [![Coverage Status](https://coveralls.io/repos/github/artur-graniszewski/pdo-proxy/badge.svg?branch=master)](https://coveralls.io/github/artur-graniszewski/pdo-proxy?branch=master) [![Code Climate](https://codeclimate.com/github/artur-graniszewski/pdo-proxy/badges/gpa.svg)](https://codeclimate.com/github/artur-graniszewski/pdo-proxy) [![Percentage of issues still open](http://isitmaintained.com/badge/open/artur-graniszewski/zeus-for-php.svg)](http://isitmaintained.com/project/artur-graniszewski/zeus-for-php "Percentage of issues still open")

# Introduction
*PDO Proxy* is a simple, event-driven PDO wrapper that allows to intercept and alter execution of all PDO methods.

Such feature can be used to:
* selectively (or entirely) mock the PDO functionality for integration tests
* intercept PDO method execution for logging or debugging purposes

The ```PDOProxy\PDO``` and ```PDOProxy\PDOStatement``` classes extend the native ```PDO``` and ```PDOStatement``` classes, therefore they are compatible with any method expecting regular ```PDO``` objects.

# Usage

After installing this library, you must provide the Proxy configuration, like so:

```php
<?php

use PDOProxy\EventManager;
use PDOProxy\ProxyConfiguration;
use PDOProxy\PDOCommand;

$ev = new EventManager();

// you can alter the output of any method, like "__construct", "query", "prepare"...
// in order to do so, you must pass method name as an event name
// please note: multiple event listeners may be attached to a single event type
$ev->addEventListener("query", function(PDOCommand $command, string $eventName) {
    // you can alter the result of any PDO method
    $event->setResult(new PDOMockStatement("query", "SELECT 1");
    $command->stopPropagation();
});

// you can intercept any method, like "__construct", "query", "prepare"...
// to do so, you must add "#pre" suffix to the event name
$ev->addEventListener("query#pre", function(PDOCommand $command, string $eventName) {
    // if you stop event propagation, the real PDO method won't be executed and the result will be taken from this callback
    if ($command->getArgs()[0] == "SELECT 1") {
        $command->stopPropagation();
    }
});

ProxyConfiguration::init($ev);
```

Now, you can initialize PDOProxy just like regular PDO object:

```php
<?php

use PDOProxy\PDO;

$pdo = new PDO("dsn", "user", "password", ["option1" => 1, "option2" => 2]);
$result = $pdo->query("SELECT 2");

// [...]
```

# Installation

Proxy can be installed in two different ways:

## via Composer: 

```
user@host:/directory$ composer require pdo-proxy/pdo-proxy
```

## by downloading source code

Source codes can be found in ZIP file under the following URL: https://github.com/artur-graniszewski/pdo-proxy/archive/master.zip


## Event types

As demonstrated in code above, each event handler gains access to two parameters, specific ```Event``` object and event name (as string).

Here is an overview of two event types raised by PDO Proxy:

### PDO Command Event:

It is raised on every execution of ```PDOProxy\PDO``` class method

```php
<?php

namespace PDOProxy;

interface PDOCommandInterface
{
    public function getArgs() : array;
    
    public function setArgs(array $args);
    
    public function getMethodName() : string;
    
    public function getResult();
    
    public function setResult($result);
}
```

The ```getArgs()``` and ```setArgs()``` methods allow to fetch and alter input parameters passed to ```PDOProxy\PDO``` method, while ```getMethodName()``` allows to check which ```PDO``` method was executed.

The ```getResult()``` and ```setResult()``` event methods allow to access and alter result that will be returned by specific ```PDO``` method.

### PDO Statement Command Event

It is raised on every execution of ```PDOProxy\PDOStatement``` class method

```php
<?php

namespace PDOProxy;

interface PDOStatementCommandInterface extends PDOCommandInterface
{   
    public function getParentArgs() : array;
    
    public function setParentArgs(array $args);
    
    public function getParentMethodName() : string;
}
```

The ```getParentArgs()``` and ```setParentArgs()``` methods allow to fetch and alter input parameters passed to ```PDOProxy\PDO``` method that created the given ```PDOProxy\PDOStatement``` object, while ```getParentMethodName()``` allows to check which ```PDO``` method was executed in the first place.

### Generic Event interface

All PDO events extend the following, generic event interface:

```php
<?php

namespace PDOProxy;

interface EventInterface
{
    public function stopPropagation();
    
    public function isPropagationStopped() : bool;
}
```

The ```stopPropagation()``` method stops further event propagation (resulting in other event listeners not being executed for a given event type). In case of event names suffixed with "#pre" sentence (like "query#pre"), the original PDO/PDOStatement method won't be executed on database, in such case result must be mocked by executing the ```setResult()``` method.

## Proxy configuration

Proxy must be configured by providing an instance of ```PDOProxy\EventManager``` to static ```init()``` method of a ```PDOProxy\ProxyConfiguration``` class (see example above). 

*Please keep in mind that instantiating ```PDOProxy\PDO``` class prior to Proxy configuration results in ```LogicException```*