Skip to content

Commit

Permalink
[Subscriber] Add history support
Browse files Browse the repository at this point in the history
  • Loading branch information
GeLoLabs committed Aug 13, 2014
1 parent 167b788 commit 0d03ae4
Show file tree
Hide file tree
Showing 13 changed files with 903 additions and 38 deletions.
89 changes: 89 additions & 0 deletions doc/events.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,3 +104,92 @@ $hasMatcher = $basicAuthSubscriber->hasMatcher();
$matcher = $basicAuthSubscriber->getMatcher();
$basicAuthSubscriber->setMatcher($matcher);
```

### History

The history subscriber is defined by the `Ivory\HttpAdapter\Event\Subscriber\HistorySubscriber` and allow you to
maintain an history of all requests/responses sent through a journal. To use it:

``` php
use Ivory\HttpAdapter\Event\Subscriber\HistorySubscriber;

$historySubscriber = new HistorySubscriber();

$httpAdapter->getEventDispatcher()->addSubscriber($historySubscriber);
```

By default, a journal is created by the subscriber but you can specify it in its constructor:

``` php
use Ivory\HttpAdapter\Event\Subscriber\History\Journal;
use Ivory\HttpAdapter\Event\Subscriber\HistorySubscriber;

$journal = new Journal();
$historySubscriber = new HistorySubscriber($journal);
```

Finally, the journal can be access or change at runtime with:

``` php
$journal = $historySubscriber->getJournal();
$historySubscriber->setJournal($journal);
```

#### Journal

As you have probably already understood, a journal is described by the
`Ivory\HttpAdapter\Event\Subscriber\History\Journal`.

First, a journal wraps a limit which represents the maximum number of
allowed entries in the journal (default: 10) but can be configured via the constructor or setter and can be accessed
via a getter:

``` php
use Ivory\HttpAdapter\Event\Subscriber\History\Journal;

$journal = new Journal(100);

$limit = $journal->getLimit();
$journal->setLimit($limit);
```

Second, the journal wraps all entries of the history according to the limit (the last entries are kept in the journal
and the last ones are dropped when a new one is added). The following API allows you to access the entries:

``` php
$hasEntries = $journal->getEntries();
$entries = $journal->getEntries();
$lastEntry = $journal->getLastEntry();
```

Third, the journal implements the `Countable` interface, so if you wants to know how many entries are in the journal,
you can use:

``` php
$count = count($journal);
```

Fourth, the journal implements the `IteratorAggregator` interface, so, you can directly access entries with the
following code but the entries are ordered from the most recent to the most old:

``` php
foreach ($journal as $entry) {
// Do what you want with the entry
}

// or

$entries = iterator_to_array($journal);
```

#### Journal entry

A journal entry is described by the `Ivory\HttpAdapter\Event\Subscriber\History\JournalEntry` and represents an entry
of the journal previously explained. It wraps the request, the response and the request execution time. To get them,
you can use:

``` php
$request = $entry->getRequest();
$response = $entry->getResponse();
$time = $entry->getTime();
```
136 changes: 136 additions & 0 deletions src/Ivory/HttpAdapter/Event/History/Journal.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
<?php

/*
* This file is part of the Ivory Http Adapter package.
*
* (c) Eric GELOEN <geloen.eric@gmail.com>
*
* For the full copyright and license information, please read the LICENSE
* file that was distributed with this source code.
*/

namespace Ivory\HttpAdapter\Event\History;

use Ivory\HttpAdapter\Message\InternalRequestInterface;
use Ivory\HttpAdapter\Message\ResponseInterface;

/**
* Journal.
*
* @author GeLo <geloen.eric@gmail.com>
*/
class Journal implements \Countable, \IteratorAggregate
{
/** @var integer */
protected $limit;

/** @var array */
protected $entries = array();

/**
* Creates a journal.
*
* @param integer $limit The limit.
*/
public function __construct($limit = 10)
{
$this->setLimit($limit);
}

/**
* Gets the limit.
*
* @return integer The limit.
*/
public function getLimit()
{
return $this->limit;
}

/**
* Sets the limit.
*
* @param integer $limit The limit.
*/
public function setLimit($limit)
{
$this->limit = $limit;
}

/**
* Clears the journal.
*/
public function clear()
{
$this->entries = array();
}

/**
* Records an entry.
*
* @param \Ivory\HttpAdapter\Message\InternalRequestInterface $request The request.
* @param \Ivory\HttpAdapter\Message\ResponseInterface $response The response.
* @param float $time The time.
*/
public function record(InternalRequestInterface $request, ResponseInterface $response, $time)
{
$this->addEntry(new JournalEntry($request, $response, $time));
}

/**
* Checks if there are entries.
*
* @return boolean TRUE if there are entries else FALSE.
*/
public function hasEntries()
{
return !empty($this->entries);
}

/**
* Gets the entries.
*
* @return array The entries.
*/
public function getEntries()
{
return $this->entries;
}

/**
* Gets the last entry.
*
* @return \Ivory\HttpAdapter\Event\History\JournalEntry|boolen The last entry or false if there is no entry.
*/
public function getLastEntry()
{
return end($this->entries);
}

/**
* Adds an entry.
*
* @param \Ivory\HttpAdapter\Event\History\JournalEntry $entry The entry.
*/
public function addEntry(JournalEntry $entry)
{
$this->entries[] = $entry;
$this->entries = array_slice($this->entries, $this->limit * -1);
}

/**
* {@inheritdoc}
*/
public function count()
{
return count($this->entries);
}

/**
* {@inheritdoc}
*/
public function getIterator()
{
return new \ArrayIterator(array_reverse($this->entries));
}
}
76 changes: 76 additions & 0 deletions src/Ivory/HttpAdapter/Event/History/JournalEntry.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
<?php

/*
* This file is part of the Ivory Http Adapter package.
*
* (c) Eric GELOEN <geloen.eric@gmail.com>
*
* For the full copyright and license information, please read the LICENSE
* file that was distributed with this source code.
*/

namespace Ivory\HttpAdapter\Event\History;

use Ivory\HttpAdapter\Message\InternalRequestInterface;
use Ivory\HttpAdapter\Message\ResponseInterface;

/**
* Journal entry.
*
* @author GeLo <geloen.eric@gmail.com>
*/
class JournalEntry
{
/** @var \Ivory\HttpAdapter\Message\InternalRequestInterface */
protected $request;

/** @var \Ivory\HttpAdapter\Message\ResponseInterface */
protected $response;

/** @var float */
protected $time;

/**
* Creates a journal entry.
*
* @param \Ivory\HttpAdapter\Message\InternalRequestInterface $request The request.
* @param \Ivory\HttpAdapter\Message\ResponseInterface $response The response.
* @param float $time The time.
*/
public function __construct(InternalRequestInterface $request, ResponseInterface $response, $time)
{
$this->request = $request;
$this->response = $response;
$this->time = $time;
}

/**
* Gets the request.
*
* @return \Ivory\HttpAdapter\Message\InternalRequestInterface The request.
*/
public function getRequest()
{
return $this->request;
}

/**
* Gets the response.
*
* @return \Ivory\HttpAdapter\Message\ResponseInterface The response.
*/
public function getResponse()
{
return $this->response;
}

/**
* Gets the time.
*
* @return float The time.
*/
public function getTime()
{
return $this->time;
}
}
62 changes: 62 additions & 0 deletions src/Ivory/HttpAdapter/Event/Subscriber/AbstractTimerSubscriber.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
<?php

/*
* This file is part of the Ivory Http Adapter package.
*
* (c) Eric GELOEN <geloen.eric@gmail.com>
*
* For the full copyright and license information, please read the LICENSE
* file that was distributed with this source code.
*/

namespace Ivory\HttpAdapter\Event\Subscriber;

use Ivory\HttpAdapter\Event\Events;
use Ivory\HttpAdapter\Event\PostSendEvent;
use Ivory\HttpAdapter\Event\PreSendEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

/**
* Abstract timer subscriber.
*
* @author GeLo <geloen.eric@gmail.com>
*/
abstract class AbstractTimerSubscriber implements EventSubscriberInterface
{
/** @var float */
protected $start;

/** @var float */
protected $time;

/**
* On pre send event.
*
* @param \Ivory\HttpAdapter\Event\PreSendEvent $event The pre send event.
*/
public function onPreSend(PreSendEvent $event)
{
$this->start = microtime(true);
}

/**
* On post send event.
*
* @param \Ivory\HttpAdapter\Event\PostSendEvent $event The post send event.
*/
public function onPostSend(PostSendEvent $event)
{
$this->time = microtime(true) - $this->start;
}

/**
* {@inheritdoc}
*/
public static function getSubscribedEvents()
{
return array(
Events::PRE_SEND => 'onPreSend',
Events::POST_SEND => 'onPostSend',
);
}
}

0 comments on commit 0d03ae4

Please sign in to comment.