1
0
mirror of https://github.com/invoiceninja/invoiceninja.git synced 2024-11-18 00:53:10 +01:00

Did more work on update logic and added timing

This commit is contained in:
Troels Liebe Bentsen 2014-10-07 23:37:06 +02:00
parent 6e59fc85df
commit 2db6fb6afd
8 changed files with 824 additions and 201 deletions

View File

@ -1,7 +1,7 @@
<?php
/**
* An helper file for Laravel 4, to provide autocomplete information to your IDE
* Generated for Laravel 4.1.25 on 2014-10-06.
* Generated for Laravel 4.1.25 on 2014-10-07.
*
* @author Barry vd. Heuvel <barryvdh@gmail.com>
* @see https://github.com/barryvdh/laravel-ide-helper

View File

@ -1189,6 +1189,7 @@ namespace {
* @property string $to_date
* @property-read \Account $account
* @property-read \User $user
* @property-read \Illuminate\Database\Eloquent\Collection|\TimesheetEvent[] $events
* @method static \Illuminate\Database\Query\Builder|\TimesheetEventSource whereId($value)
* @method static \Illuminate\Database\Query\Builder|\TimesheetEventSource whereUserId($value)
* @method static \Illuminate\Database\Query\Builder|\TimesheetEventSource whereAccountId($value)

View File

@ -3,6 +3,7 @@
use Illuminate\Console\Command;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputArgument;
use PHPBenchTime\Timer;
class ImportTimesheetData extends Command {
@ -47,7 +48,6 @@ class ImportTimesheetData extends Command {
$code->name = $name;
$project->codes()->save($code);
}
#Project::createNew($user);
}
if (!TimesheetEventSource::find(1)) {
@ -55,9 +55,6 @@ class ImportTimesheetData extends Command {
$oldevent_sources = json_decode(file_get_contents("/home/tlb/git/itktime/employes.json"), true);
//array_shift($oldevent_sources);
//array_pop($oldevent_sources);
foreach ($oldevent_sources as $source) {
$event_source = TimesheetEventSource::createNew($user);
$event_source->name = $source['name'];
@ -71,35 +68,46 @@ class ImportTimesheetData extends Command {
// Add all URL's to Curl
$this->info("Download ICAL feeds");
$T = new Timer;
$T->start();
$T->lap("Get Event Sources");
$event_sources = TimesheetEventSource::all(); // TODO: Filter based on ical feeds
$T->lap("Get ICAL responses");
$urls = [];
$event_sources->map(function($item) use(&$urls) {
$urls[] = $item->url;
});
$results = $this->curlGetUrls($urls);
$icalresponses = TimesheetUtils::curlGetUrls($urls);
// Fetch all codes so we can do a quick lookup
$T->lap("Fetch all codes so we can do a quick lookup");
$codes = array();
ProjectCode::all()->map(function($item) use(&$codes) {
$codes[$item->name] = $item;
});
//FIXME: Make sure we keep track of duplicate UID's so we don't fail when inserting them to the database
$this->info("Start parsing ICAL files");
foreach ($event_sources as $i => $event_source) {
if (!is_array($results[$i])) {
if (!is_array($icalresponses[$i])) {
$this->info("Find events in " . $event_source->name);
file_put_contents("/tmp/" . $event_source->name . ".ical", $results[$i]);
if (preg_match_all('/BEGIN:VEVENT\r?\n(.+?)\r?\nEND:VEVENT/s', $results[$i], $icalmatches)) {
$this->info("Found ".(count($icalmatches[1])-1)." events\n");
// Fetch all uids so we can do a quick lookup
file_put_contents("/tmp/" . $event_source->name . ".ical", $icalresponses[$i]); // FIXME: Remove
$T->lap("Split on events for ".$event_source->name);
if (preg_match_all('/BEGIN:VEVENT\r?\n(.+?)\r?\nEND:VEVENT/s', $icalresponses[$i], $icalmatches)) {
$this->info("Found ".(count($icalmatches[1])-1)." events");
$T->lap("Fetch all uids so we can do a quick lookup ".$event_source->name);
$uids = [];
$event_source->events()->get(['uid', 'org_updated_at'])->map(function($item) use(&$uids) {
$event_source->events()->get(['uid', 'org_updated_at', 'updated_data_at'])->map(function($item) use(&$uids) {
if($item->org_updated_at > $item->updated_data_at) {
$uids[$item->uid] = $item->org_updated_at;
} else {
$uids[$item->uid] = $item->updated_data_at;
}
});
$deleted = $uids;
// Loop over all the found events
$T->lap("Parse events for ".$event_source->name);
foreach ($icalmatches[1] as $eventstr) {
//print "---\n";
//print $eventstr."\n";
@ -143,11 +151,15 @@ class ImportTimesheetData extends Command {
switch ($key) {
case 'dtstart':
$event->start_date = $dt;
if($timezone) {
$event->org_start_date_timezone = $timezone;
}
break;
case 'dtend':
$event->end_date = $dt;
if($timezone) {
$event->org_end_date_timezone = $timezone;
}
break;
case 'created':
$event->org_created_at = $dt;
@ -168,24 +180,6 @@ class ImportTimesheetData extends Command {
}
}
// Check for events we allready have
if (isset($uids[$event->uid])) {
$db_event_org_updated_at = new DateTime($uids[$event->uid], new DateTimeZone('UTC'));
if($event->org_updated_at <= $db_event_org_updated_at) {
// Same or older version of new event so skip
continue;
} else {
var_dump($event->uid);
var_dump($uids[$event->uid]);
var_dump($event);
// updated version of the event
echo "update version of the event\n";
}
}
$uids[$event->uid] = $event->org_updated_at;
// Calculate number of hours
$di = $event->end_date->diff($event->start_date);
$event->hours = $di->h + $di->i / 60;
@ -193,7 +187,9 @@ class ImportTimesheetData extends Command {
// Copy data to new object
$event->org_data = $eventstr;
$event->summary = $title;
$event->description = $title;
if(isset($data['description'])) {
$event->description = $data['description'];
}
$event->org_code = $codename;
$event->owner = $event_source->owner;
$event->timesheet_event_source_id = $event_source->id;
@ -205,12 +201,58 @@ class ImportTimesheetData extends Command {
$event->location = $data['location'];
}
// Check for events we already have
if (isset($uids[$event->uid])) {
// Remove from deleted list
unset($deleted[$event->uid]);
// See if the event has been updated compared to the one in the database
$db_event_org_updated_at = new DateTime($uids[$event->uid], new DateTimeZone('UTC'));
// Check if same or older version of new event so skip
if($event->org_updated_at <= $db_event_org_updated_at) {
// SKIP
// Updated version of the event
} else {
// Get the old event from the database
/* @var $db_event TimesheetEvent */
$db_event = $event_source->events()->where('uid', $event->uid)->firstOrFail();
$changes = $db_event->toChangesArray($event);
// Make sure it's more than the org_updated_at that has been changed
if (count($changes) > 1) {
// Check if we have changed the event in the database or used it in a timesheet
if ($db_event->manualedit || $db_event->timesheet) {
$this->info("Updated Data");
$db_event->updated_data = $event->org_data;
$db_event->updated_data_at = $event->org_updated_at;
// Update the db_event with the changes
} else {
$this->info("Updated Event");
foreach ($changes as $key => $value) {
if($value == null) {
unset($db_event->$key);
} else {
$db_event->$key = $value;
}
}
}
} else {
$this->info("Nothing Changed");
// Nothing has been changed so update the org_updated_at
$db_event->org_updated_at = $changes['org_updated_at'];
}
$db_event->save();
}
} else {
try {
$this->info("Save event: ".$event->summary);
//if($event->uid == '2nvv4qjnlc293vq3h2833uslhc@google.com') {
//var_dump($event);
$this->info("New event: " . $event->summary);
$event->save();
//}
} catch (Exception $ex) {
echo "'" . $event->summary . "'\n";
var_dump($data);
@ -219,83 +261,32 @@ class ImportTimesheetData extends Command {
exit(0);
}
}
// Add new uid to know uids
$uids[$event->uid] = $event->org_updated_at;
}
}
}
$this->info("Deleted ".count($deleted). " events");
foreach($deleted as $uid => $lastupdated_date) {
echo "$uid: $lastupdated_date\n";
}
} else {
// Parse error
}
} else {
// Curl Error
}
}
foreach($T->end()['laps'] as $lap) {
echo number_format($lap['total'], 3)." : {$lap['name']}\n";
}
$this->info('Done');
}
private function curlGetUrls($urls = [], $timeout = 30) {
// Create muxer
$results = [];
$multi = curl_multi_init();
$handles = [];
$ch2idx = [];
try {
foreach ($urls as $i => $url) {
// Create new handle and add to muxer
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_ENCODING, "gzip");
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
curl_setopt($ch, CURLOPT_TIMEOUT, $timeout); //timeout in seconds
curl_multi_add_handle($multi, $ch);
$handles[(int) $ch] = $ch;
$ch2idx[(int) $ch] = $i;
}
// Do initial connect
$still_running = true;
while ($still_running) {
// Do curl stuff
while (($mrc = curl_multi_exec($multi, $still_running)) === CURLM_CALL_MULTI_PERFORM);
if ($mrc !== CURLM_OK) {
break;
}
// Try to read from handles that are ready
while ($info = curl_multi_info_read($multi)) {
if ($info["result"] == CURLE_OK) {
$results[$ch2idx[(int) $info["handle"]]] = curl_multi_getcontent($info["handle"]);
} else {
if (CURLE_UNSUPPORTED_PROTOCOL == $info["result"]) {
$results[$ch2idx[(int) $info["handle"]]] = [$info["result"], "Unsupported protocol"];
} else if (CURLE_URL_MALFORMAT == $info["result"]) {
$results[$ch2idx[(int) $info["handle"]]] = [$info["result"], "Malform url"];
} else if (CURLE_COULDNT_RESOLVE_HOST == $info["result"]) {
$results[$ch2idx[(int) $info["handle"]]] = [$info["result"], "Could not resolve host"];
} else if (CURLE_OPERATION_TIMEDOUT == $info["result"]) {
$results[$ch2idx[(int) $info["handle"]]] = [$info["result"], "Timed out waiting for operations to finish"];
} else {
$results[$ch2idx[(int) $info["handle"]]] = [$info["result"], "Unknown curl error code"];
}
}
}
// Sleep until
if (($rs = curl_multi_select($multi)) === -1) {
usleep(20); // select failed for some reason, so we sleep for 20ms and run some more curl stuff
}
}
} finally {
foreach ($handles as $chi => $ch) {
curl_multi_remove_handle($multi, $ch);
}
curl_multi_close($multi);
}
return $results;
}
protected function getArguments() {
return array(
);

View File

@ -109,6 +109,7 @@ class AddTimesheets extends Migration {
# Calculated values
$t->decimal('hours');
$t->float('discount');
$t->boolean('manualedit');
// Original data
$t->string('org_code');
@ -120,7 +121,9 @@ class AddTimesheets extends Migration {
// Error and merge handling
$t->string('import_error')->nullable();
$t->string('import_warning')->nullable();
$t->text('updated_data')->nullable();
$t->timeStamp('updated_data_at')->default('0000-00-00T00:00:00');
$t->foreign('account_id')->references('id')->on('accounts');
$t->foreign('user_id')->references('id')->on('users')->onDelete('cascade');

View File

@ -52,4 +52,68 @@ class TimesheetUtils
return [$dt, $timezone];
}
public static function curlGetUrls($urls = [], $timeout = 30) {
// Create muxer
$results = [];
$multi = curl_multi_init();
$handles = [];
$ch2idx = [];
try {
foreach ($urls as $i => $url) {
// Create new handle and add to muxer
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_ENCODING, "gzip");
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
curl_setopt($ch, CURLOPT_TIMEOUT, $timeout); //timeout in seconds
curl_multi_add_handle($multi, $ch);
$handles[(int) $ch] = $ch;
$ch2idx[(int) $ch] = $i;
}
// Do initial connect
$still_running = true;
while ($still_running) {
// Do curl stuff
while (($mrc = curl_multi_exec($multi, $still_running)) === CURLM_CALL_MULTI_PERFORM);
if ($mrc !== CURLM_OK) {
break;
}
// Try to read from handles that are ready
while ($info = curl_multi_info_read($multi)) {
if ($info["result"] == CURLE_OK) {
$results[$ch2idx[(int) $info["handle"]]] = curl_multi_getcontent($info["handle"]);
} else {
if (CURLE_UNSUPPORTED_PROTOCOL == $info["result"]) {
$results[$ch2idx[(int) $info["handle"]]] = [$info["result"], "Unsupported protocol"];
} else if (CURLE_URL_MALFORMAT == $info["result"]) {
$results[$ch2idx[(int) $info["handle"]]] = [$info["result"], "Malform url"];
} else if (CURLE_COULDNT_RESOLVE_HOST == $info["result"]) {
$results[$ch2idx[(int) $info["handle"]]] = [$info["result"], "Could not resolve host"];
} else if (CURLE_OPERATION_TIMEDOUT == $info["result"]) {
$results[$ch2idx[(int) $info["handle"]]] = [$info["result"], "Timed out waiting for operations to finish"];
} else {
$results[$ch2idx[(int) $info["handle"]]] = [$info["result"], "Unknown curl error code"];
}
}
}
// Sleep until
if (($rs = curl_multi_select($multi)) === -1) {
usleep(20); // select failed for some reason, so we sleep for 20ms and run some more curl stuff
}
}
} finally {
foreach ($handles as $chi => $ch) {
curl_multi_remove_handle($multi, $ch);
}
curl_multi_close($multi);
}
return $results;
}
}

View File

@ -73,4 +73,57 @@ class TimesheetEvent extends Eloquent
return $entity;
}
public function toChangesArray(TimesheetEvent $other)
{
$attributes_old = parent::toArray();
$attributes_new = $other->toArray();
$skip_keys = ['id' => 1, 'created_at' => 1, 'updated_at' => 1, 'deleted_at' => 1, 'org_data' => 1, 'update_data' => 1];
$zeroisempty_keys = ['discount' => 1];
$result = [];
// Find all the values that where changed or deleted
foreach ($attributes_old as $key => $value) {
// Skip null values, keys we don't care about and 0 value keys that means they are not used
if(empty($value) || isset($skip_keys[$key])|| (isset($zeroisempty_keys[$key]) && $value) ) {
continue;
}
// Compare values if it exists in the new array
if(isset($attributes_new[$key]) || array_key_exists($key, $attributes_new)) {
if($value instanceof \DateTime && $attributes_new[$key] instanceof \DateTime) {
if($value != $attributes_new[$key]) {
$result[$key] = $attributes_new[$key]->format("Y-m-d H:i:s");
}
} elseif($value instanceof \DateTime && is_string($attributes_new[$key])) {
if($value->format("Y-m-d H:i:s") != $attributes_new[$key]) {
$result[$key] = $attributes_new[$key];
}
} elseif(is_string($value) && $attributes_new[$key] instanceof \DateTime) {
if($attributes_new[$key]->format("Y-m-d H:i:s") != $value) {
$result[$key] = $attributes_new[$key]->format("Y-m-d H:i:s");
}
} elseif($value != $attributes_new[$key]) {
$result[$key] = $attributes_new[$key];
}
} else {
$result[$key] = null;
}
}
// Find all the values that where deleted
foreach ($attributes_new as $key => $value) {
if(isset($skip_keys[$key])) {
continue;
}
if(!isset($attributes_old[$key])) {
$result[$key] = $value;
}
}
return $result;
}
}

View File

@ -20,7 +20,8 @@
"intervention/image": "1.x",
"webpatser/laravel-countries": "dev-master",
"barryvdh/laravel-ide-helper": "1.*",
"doctrine/dbal": "~2.3"
"doctrine/dbal": "~2.3",
"jsanc623/phpbenchtime": "2.x"
},
"require-dev": {
"codeception/codeception": "dev-master"
@ -48,9 +49,8 @@
"post-update-cmd": [
"php artisan clear-compiled",
"php artisan ide-helper:generate",
"php artisan ide-helper:models -N",
"php artisan optimize",
"php artisan debugbar:publish"
"php artisan debugbar:publish",
"php artisan optimize"
],
"post-create-project-cmd": [
"php artisan key:generate"

669
composer.lock generated
View File

@ -4,7 +4,7 @@
"Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically"
],
"hash": "5ada8e160b5ef619b338492b45593f75",
"hash": "65f2ef5897c7ec4d7396b49a429fb1c6",
"packages": [
{
"name": "anahkiasen/former",
@ -156,12 +156,12 @@
"source": {
"type": "git",
"url": "https://github.com/barryvdh/laravel-debugbar.git",
"reference": "c5372628184d5b76e247a73efd1d915a7d26ab96"
"reference": "1a37b2f1dd66d36c5b8f19f4ab2f38cfc794a238"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/barryvdh/laravel-debugbar/zipball/c5372628184d5b76e247a73efd1d915a7d26ab96",
"reference": "c5372628184d5b76e247a73efd1d915a7d26ab96",
"url": "https://api.github.com/repos/barryvdh/laravel-debugbar/zipball/1a37b2f1dd66d36c5b8f19f4ab2f38cfc794a238",
"reference": "1a37b2f1dd66d36c5b8f19f4ab2f38cfc794a238",
"shasum": ""
},
"require": {
@ -202,7 +202,7 @@
"profiler",
"webprofiler"
],
"time": "2014-09-19 13:55:20"
"time": "2014-10-07 14:21:49"
},
{
"name": "barryvdh/laravel-ide-helper",
@ -401,6 +401,479 @@
"notification-url": "https://packagist.org/downloads/",
"time": "2014-01-17 12:21:18"
},
{
"name": "doctrine/annotations",
"version": "dev-master",
"source": {
"type": "git",
"url": "https://github.com/doctrine/annotations.git",
"reference": "6a6bec0670bb6e71a263b08bc1b98ea242928633"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/annotations/zipball/6a6bec0670bb6e71a263b08bc1b98ea242928633",
"reference": "6a6bec0670bb6e71a263b08bc1b98ea242928633",
"shasum": ""
},
"require": {
"doctrine/lexer": "1.*",
"php": ">=5.3.2"
},
"require-dev": {
"doctrine/cache": "1.*",
"phpunit/phpunit": "4.*"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.3.x-dev"
}
},
"autoload": {
"psr-0": {
"Doctrine\\Common\\Annotations\\": "lib/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Roman Borschel",
"email": "roman@code-factory.org"
},
{
"name": "Benjamin Eberlei",
"email": "kontakt@beberlei.de"
},
{
"name": "Guilherme Blanco",
"email": "guilhermeblanco@gmail.com"
},
{
"name": "Jonathan Wage",
"email": "jonwage@gmail.com"
},
{
"name": "Johannes Schmitt",
"email": "schmittjoh@gmail.com"
}
],
"description": "Docblock Annotations Parser",
"homepage": "http://www.doctrine-project.org",
"keywords": [
"annotations",
"docblock",
"parser"
],
"time": "2014-09-25 16:45:30"
},
{
"name": "doctrine/cache",
"version": "dev-master",
"source": {
"type": "git",
"url": "https://github.com/doctrine/cache.git",
"reference": "f7a1d660c521461b835dc31af0f6c9836769e917"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/cache/zipball/f7a1d660c521461b835dc31af0f6c9836769e917",
"reference": "f7a1d660c521461b835dc31af0f6c9836769e917",
"shasum": ""
},
"require": {
"php": ">=5.3.2"
},
"conflict": {
"doctrine/common": ">2.2,<2.4"
},
"require-dev": {
"phpunit/phpunit": ">=3.7",
"satooshi/php-coveralls": "~0.6"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.4.x-dev"
}
},
"autoload": {
"psr-0": {
"Doctrine\\Common\\Cache\\": "lib/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Roman Borschel",
"email": "roman@code-factory.org"
},
{
"name": "Benjamin Eberlei",
"email": "kontakt@beberlei.de"
},
{
"name": "Guilherme Blanco",
"email": "guilhermeblanco@gmail.com"
},
{
"name": "Jonathan Wage",
"email": "jonwage@gmail.com"
},
{
"name": "Johannes Schmitt",
"email": "schmittjoh@gmail.com"
}
],
"description": "Caching library offering an object-oriented API for many cache backends",
"homepage": "http://www.doctrine-project.org",
"keywords": [
"cache",
"caching"
],
"time": "2014-09-29 13:28:56"
},
{
"name": "doctrine/collections",
"version": "dev-master",
"source": {
"type": "git",
"url": "https://github.com/doctrine/collections.git",
"reference": "8c5148e0ef8cee4afe86d45ba98f7b6d96e780d0"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/collections/zipball/8c5148e0ef8cee4afe86d45ba98f7b6d96e780d0",
"reference": "8c5148e0ef8cee4afe86d45ba98f7b6d96e780d0",
"shasum": ""
},
"require": {
"php": ">=5.3.2"
},
"require-dev": {
"phpunit/phpunit": "~4.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.2.x-dev"
}
},
"autoload": {
"psr-0": {
"Doctrine\\Common\\Collections\\": "lib/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Roman Borschel",
"email": "roman@code-factory.org"
},
{
"name": "Benjamin Eberlei",
"email": "kontakt@beberlei.de"
},
{
"name": "Guilherme Blanco",
"email": "guilhermeblanco@gmail.com"
},
{
"name": "Jonathan Wage",
"email": "jonwage@gmail.com"
},
{
"name": "Johannes Schmitt",
"email": "schmittjoh@gmail.com"
}
],
"description": "Collections Abstraction library",
"homepage": "http://www.doctrine-project.org",
"keywords": [
"array",
"collections",
"iterator"
],
"time": "2014-09-24 12:11:27"
},
{
"name": "doctrine/common",
"version": "2.4.x-dev",
"source": {
"type": "git",
"url": "https://github.com/doctrine/common.git",
"reference": "ae92d076442e27b6910dd86a1292a8867cf5cfe4"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/common/zipball/ae92d076442e27b6910dd86a1292a8867cf5cfe4",
"reference": "ae92d076442e27b6910dd86a1292a8867cf5cfe4",
"shasum": ""
},
"require": {
"doctrine/annotations": "1.*",
"doctrine/cache": "1.*",
"doctrine/collections": "1.*",
"doctrine/inflector": "1.*",
"doctrine/lexer": "1.*",
"php": ">=5.3.2"
},
"require-dev": {
"phpunit/phpunit": "~3.7"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.4.x-dev"
}
},
"autoload": {
"psr-0": {
"Doctrine\\Common\\": "lib/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Jonathan Wage",
"email": "jonwage@gmail.com",
"homepage": "http://www.jwage.com/",
"role": "Creator"
},
{
"name": "Guilherme Blanco",
"email": "guilhermeblanco@gmail.com",
"homepage": "http://www.instaclick.com"
},
{
"name": "Roman Borschel",
"email": "roman@code-factory.org"
},
{
"name": "Benjamin Eberlei",
"email": "kontakt@beberlei.de"
},
{
"name": "Johannes Schmitt",
"email": "schmittjoh@gmail.com",
"homepage": "https://github.com/schmittjoh",
"role": "Developer of wrapped JMSSerializerBundle"
}
],
"description": "Common Library for Doctrine projects",
"homepage": "http://www.doctrine-project.org",
"keywords": [
"annotations",
"collections",
"eventmanager",
"persistence",
"spl"
],
"time": "2014-05-21 19:29:23"
},
{
"name": "doctrine/dbal",
"version": "dev-master",
"source": {
"type": "git",
"url": "https://github.com/doctrine/dbal.git",
"reference": "7175964c30f4fd54c90f6f9c7c6f7bf49fc1c939"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/dbal/zipball/7175964c30f4fd54c90f6f9c7c6f7bf49fc1c939",
"reference": "7175964c30f4fd54c90f6f9c7c6f7bf49fc1c939",
"shasum": ""
},
"require": {
"doctrine/common": "2.4.*",
"php": ">=5.3.2"
},
"require-dev": {
"phpunit/phpunit": "4.0.*",
"symfony/console": "2.*"
},
"suggest": {
"symfony/console": "For helpful console commands such as SQL execution and import of files."
},
"bin": [
"bin/doctrine-dbal"
],
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.5.x-dev"
}
},
"autoload": {
"psr-0": {
"Doctrine\\DBAL\\": "lib/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Roman Borschel",
"email": "roman@code-factory.org"
},
{
"name": "Benjamin Eberlei",
"email": "kontakt@beberlei.de"
},
{
"name": "Guilherme Blanco",
"email": "guilhermeblanco@gmail.com"
},
{
"name": "Jonathan Wage",
"email": "jonwage@gmail.com"
}
],
"description": "Database Abstraction Layer",
"homepage": "http://www.doctrine-project.org",
"keywords": [
"database",
"dbal",
"persistence",
"queryobject"
],
"time": "2014-09-17 17:17:21"
},
{
"name": "doctrine/inflector",
"version": "dev-master",
"source": {
"type": "git",
"url": "https://github.com/doctrine/inflector.git",
"reference": "8a0b96e65d2399d6f95b75de11134843a2c61feb"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/inflector/zipball/8a0b96e65d2399d6f95b75de11134843a2c61feb",
"reference": "8a0b96e65d2399d6f95b75de11134843a2c61feb",
"shasum": ""
},
"require": {
"php": ">=5.3.2"
},
"require-dev": {
"phpunit/phpunit": "4.*"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
},
"autoload": {
"psr-0": {
"Doctrine\\Common\\Inflector\\": "lib/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Roman Borschel",
"email": "roman@code-factory.org"
},
{
"name": "Benjamin Eberlei",
"email": "kontakt@beberlei.de"
},
{
"name": "Guilherme Blanco",
"email": "guilhermeblanco@gmail.com"
},
{
"name": "Jonathan Wage",
"email": "jonwage@gmail.com"
},
{
"name": "Johannes Schmitt",
"email": "schmittjoh@gmail.com"
}
],
"description": "Common String Manipulations with regard to casing and singular/plural rules.",
"homepage": "http://www.doctrine-project.org",
"keywords": [
"inflection",
"pluralize",
"singularize",
"string"
],
"time": "2014-10-05 18:49:49"
},
{
"name": "doctrine/lexer",
"version": "dev-master",
"source": {
"type": "git",
"url": "https://github.com/doctrine/lexer.git",
"reference": "83893c552fd2045dd78aef794c31e694c37c0b8c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/lexer/zipball/83893c552fd2045dd78aef794c31e694c37c0b8c",
"reference": "83893c552fd2045dd78aef794c31e694c37c0b8c",
"shasum": ""
},
"require": {
"php": ">=5.3.2"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
},
"autoload": {
"psr-0": {
"Doctrine\\Common\\Lexer\\": "lib/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Roman Borschel",
"email": "roman@code-factory.org"
},
{
"name": "Guilherme Blanco",
"email": "guilhermeblanco@gmail.com"
},
{
"name": "Johannes Schmitt",
"email": "schmittjoh@gmail.com"
}
],
"description": "Base library for a lexer that can be used in Top-Down, Recursive Descent Parsers.",
"homepage": "http://www.doctrine-project.org",
"keywords": [
"lexer",
"parser"
],
"time": "2014-09-09 13:34:57"
},
{
"name": "filp/whoops",
"version": "1.0.10",
@ -790,6 +1263,46 @@
],
"time": "2013-10-09 04:20:00"
},
{
"name": "jsanc623/phpbenchtime",
"version": "2.0.0",
"source": {
"type": "git",
"url": "https://github.com/jsanc623/PHPBenchTime.git",
"reference": "e8cba5217fe5998ae1926c2cb2202d8d973db1f1"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/jsanc623/PHPBenchTime/zipball/e8cba5217fe5998ae1926c2cb2202d8d973db1f1",
"reference": "e8cba5217fe5998ae1926c2cb2202d8d973db1f1",
"shasum": ""
},
"type": "library",
"autoload": {
"psr-0": {
"": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Juan Sanchez",
"email": "juan.sanchez@juanleonardosanchez.com"
}
],
"description": "A light benchmark timer class for PHP.",
"keywords": [
"benchmark",
"benchtime",
"profiler",
"stopwatch",
"timer"
],
"time": "2014-07-23 20:52:24"
},
{
"name": "laravel/framework",
"version": "v4.1.25",
@ -1027,12 +1540,12 @@
"source": {
"type": "git",
"url": "https://github.com/Seldaek/monolog.git",
"reference": "b3f039339d7a8173c7b441dbaa572ccacb712b54"
"reference": "940cbe15abe36924e5693abb585215bb322686a7"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Seldaek/monolog/zipball/b3f039339d7a8173c7b441dbaa572ccacb712b54",
"reference": "b3f039339d7a8173c7b441dbaa572ccacb712b54",
"url": "https://api.github.com/repos/Seldaek/monolog/zipball/940cbe15abe36924e5693abb585215bb322686a7",
"reference": "940cbe15abe36924e5693abb585215bb322686a7",
"shasum": ""
},
"require": {
@ -1091,7 +1604,7 @@
"logging",
"psr-3"
],
"time": "2014-09-10 15:41:01"
"time": "2014-10-04 15:43:06"
},
{
"name": "nesbot/carbon",
@ -1923,12 +2436,12 @@
"source": {
"type": "git",
"url": "https://github.com/thephpleague/omnipay-mollie.git",
"reference": "4d49e5600adc0990ced6ef368efa46883a9171fc"
"reference": "646a35bf726fd29f25df163ee1c9f37c811a3443"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/thephpleague/omnipay-mollie/zipball/4d49e5600adc0990ced6ef368efa46883a9171fc",
"reference": "4d49e5600adc0990ced6ef368efa46883a9171fc",
"url": "https://api.github.com/repos/thephpleague/omnipay-mollie/zipball/646a35bf726fd29f25df163ee1c9f37c811a3443",
"reference": "646a35bf726fd29f25df163ee1c9f37c811a3443",
"shasum": ""
},
"require": {
@ -1972,7 +2485,7 @@
"pay",
"payment"
],
"time": "2014-09-17 00:39:49"
"time": "2014-10-07 13:55:30"
},
{
"name": "omnipay/multisafepay",
@ -3351,12 +3864,12 @@
"source": {
"type": "git",
"url": "https://github.com/symfony/ClassLoader.git",
"reference": "9410b3fadff5da57b43db601ec7f121960b5b3f5"
"reference": "fe9ec2bf22e4279892ac3d83bc584e539a79fa41"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/ClassLoader/zipball/9410b3fadff5da57b43db601ec7f121960b5b3f5",
"reference": "9410b3fadff5da57b43db601ec7f121960b5b3f5",
"url": "https://api.github.com/repos/symfony/ClassLoader/zipball/fe9ec2bf22e4279892ac3d83bc584e539a79fa41",
"reference": "fe9ec2bf22e4279892ac3d83bc584e539a79fa41",
"shasum": ""
},
"require": {
@ -3392,7 +3905,7 @@
],
"description": "Symfony ClassLoader Component",
"homepage": "http://symfony.com",
"time": "2014-09-22 11:59:59"
"time": "2014-10-01 05:53:11"
},
{
"name": "symfony/console",
@ -3613,12 +4126,12 @@
"source": {
"type": "git",
"url": "https://github.com/symfony/EventDispatcher.git",
"reference": "ea86d91a10c5737a1e043aa29fe05837f942d163"
"reference": "e133748fd9165e24f8e9498ef5862f8bd37004e5"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/EventDispatcher/zipball/ea86d91a10c5737a1e043aa29fe05837f942d163",
"reference": "ea86d91a10c5737a1e043aa29fe05837f942d163",
"url": "https://api.github.com/repos/symfony/EventDispatcher/zipball/e133748fd9165e24f8e9498ef5862f8bd37004e5",
"reference": "e133748fd9165e24f8e9498ef5862f8bd37004e5",
"shasum": ""
},
"require": {
@ -3662,7 +4175,7 @@
],
"description": "Symfony EventDispatcher Component",
"homepage": "http://symfony.com",
"time": "2014-09-28 16:15:31"
"time": "2014-10-04 06:08:58"
},
{
"name": "symfony/filesystem",
@ -4248,12 +4761,12 @@
"source": {
"type": "git",
"url": "https://github.com/doctrine/instantiator.git",
"reference": "26404e0c90565b614ee76b988b9bc8790d77f590"
"reference": "4bdc0421209a00e6f425f4c3554d1b0df3a7e897"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/instantiator/zipball/26404e0c90565b614ee76b988b9bc8790d77f590",
"reference": "26404e0c90565b614ee76b988b9bc8790d77f590",
"url": "https://api.github.com/repos/doctrine/instantiator/zipball/4bdc0421209a00e6f425f4c3554d1b0df3a7e897",
"reference": "4bdc0421209a00e6f425f4c3554d1b0df3a7e897",
"shasum": ""
},
"require": {
@ -4294,7 +4807,7 @@
"constructor",
"instantiate"
],
"time": "2014-08-25 15:09:25"
"time": "2014-10-05 00:20:37"
},
{
"name": "facebook/webdriver",
@ -4342,12 +4855,12 @@
"source": {
"type": "git",
"url": "https://github.com/guzzle/guzzle.git",
"reference": "514ee50a5aaa46f8006bc5dc1c9a39d55202983d"
"reference": "66fd916e9f9130bc22c51450476823391cb2f67c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/guzzle/guzzle/zipball/514ee50a5aaa46f8006bc5dc1c9a39d55202983d",
"reference": "514ee50a5aaa46f8006bc5dc1c9a39d55202983d",
"url": "https://api.github.com/repos/guzzle/guzzle/zipball/66fd916e9f9130bc22c51450476823391cb2f67c",
"reference": "66fd916e9f9130bc22c51450476823391cb2f67c",
"shasum": ""
},
"require": {
@ -4399,7 +4912,7 @@
"rest",
"web service"
],
"time": "2014-09-25 04:48:09"
"time": "2014-10-05 19:29:14"
},
{
"name": "guzzlehttp/streams",
@ -4460,21 +4973,21 @@
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
"reference": "0f0063f283597359ea5cb4e1afdf1a14b0ac5038"
"reference": "28d21b57c189cb72829056353de603c4d4da55a0"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/0f0063f283597359ea5cb4e1afdf1a14b0ac5038",
"reference": "0f0063f283597359ea5cb4e1afdf1a14b0ac5038",
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/28d21b57c189cb72829056353de603c4d4da55a0",
"reference": "28d21b57c189cb72829056353de603c4d4da55a0",
"shasum": ""
},
"require": {
"php": ">=5.3.3",
"phpunit/php-file-iterator": "~1.3.1",
"phpunit/php-text-template": "~1.2.0",
"phpunit/php-token-stream": "~1.2.2",
"sebastian/environment": "~1.0.0",
"sebastian/version": "~1.0.3"
"phpunit/php-file-iterator": "~1.3",
"phpunit/php-text-template": "~1.2",
"phpunit/php-token-stream": "~1.3",
"sebastian/environment": "~1.0",
"sebastian/version": "~1.0"
},
"require-dev": {
"ext-xdebug": ">=2.1.4",
@ -4514,7 +5027,7 @@
"testing",
"xunit"
],
"time": "2014-09-01 22:04:32"
"time": "2014-10-05 10:46:54"
},
{
"name": "phpunit/php-file-iterator",
@ -4651,45 +5164,44 @@
},
{
"name": "phpunit/php-token-stream",
"version": "1.2.2",
"version": "dev-master",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-token-stream.git",
"reference": "ad4e1e23ae01b483c16f600ff1bebec184588e32"
"reference": "f8d5d08c56de5cfd592b3340424a81733259a876"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/ad4e1e23ae01b483c16f600ff1bebec184588e32",
"reference": "ad4e1e23ae01b483c16f600ff1bebec184588e32",
"url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/f8d5d08c56de5cfd592b3340424a81733259a876",
"reference": "f8d5d08c56de5cfd592b3340424a81733259a876",
"shasum": ""
},
"require": {
"ext-tokenizer": "*",
"php": ">=5.3.3"
},
"require-dev": {
"phpunit/phpunit": "~4.2"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.2-dev"
"dev-master": "1.3-dev"
}
},
"autoload": {
"classmap": [
"PHP/"
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"include-path": [
""
],
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Sebastian Bergmann",
"email": "sb@sebastian-bergmann.de",
"role": "lead"
"email": "sebastian@phpunit.de"
}
],
"description": "Wrapper around PHP's tokenizer extension.",
@ -4697,7 +5209,7 @@
"keywords": [
"tokenizer"
],
"time": "2014-03-03 05:10:30"
"time": "2014-08-31 06:12:13"
},
{
"name": "phpunit/phpunit",
@ -4705,12 +5217,12 @@
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git",
"reference": "5ee7af96d62a3fe9cf466fab1b505ac8dc1796c6"
"reference": "f75e6b2e0764bcf4faa5082f4b60d5e7cf0959bb"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/5ee7af96d62a3fe9cf466fab1b505ac8dc1796c6",
"reference": "5ee7af96d62a3fe9cf466fab1b505ac8dc1796c6",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/f75e6b2e0764bcf4faa5082f4b60d5e7cf0959bb",
"reference": "f75e6b2e0764bcf4faa5082f4b60d5e7cf0959bb",
"shasum": ""
},
"require": {
@ -4724,10 +5236,10 @@
"phpunit/php-file-iterator": "~1.3.1",
"phpunit/php-text-template": "~1.2",
"phpunit/php-timer": "~1.0.2",
"phpunit/phpunit-mock-objects": "2.3.*@dev",
"phpunit/phpunit-mock-objects": "2.4.*@dev",
"sebastian/comparator": "~1.0",
"sebastian/diff": "~1.1",
"sebastian/environment": "~1.0",
"sebastian/environment": "~1.1",
"sebastian/exporter": "~1.0",
"sebastian/global-state": "1.0.*@dev",
"sebastian/version": "~1.0",
@ -4768,7 +5280,7 @@
"testing",
"xunit"
],
"time": "2014-09-19 08:44:28"
"time": "2014-10-07 09:30:07"
},
{
"name": "phpunit/phpunit-mock-objects",
@ -4776,21 +5288,21 @@
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git",
"reference": "3d40ae857a3941ede714be45079e85f9e956b4b3"
"reference": "96c5b81f9842f38fe6c73ad0020306cc4862a9e3"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/3d40ae857a3941ede714be45079e85f9e956b4b3",
"reference": "3d40ae857a3941ede714be45079e85f9e956b4b3",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/96c5b81f9842f38fe6c73ad0020306cc4862a9e3",
"reference": "96c5b81f9842f38fe6c73ad0020306cc4862a9e3",
"shasum": ""
},
"require": {
"doctrine/instantiator": "~1.0,>=1.0.1",
"doctrine/instantiator": "~1.0,>=1.0.2",
"php": ">=5.3.3",
"phpunit/php-text-template": "~1.2"
},
"require-dev": {
"phpunit/phpunit": "4.3.*@dev"
"phpunit/phpunit": "4.4.*@dev"
},
"suggest": {
"ext-soap": "*"
@ -4798,7 +5310,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.3.x-dev"
"dev-master": "2.4.x-dev"
}
},
"autoload": {
@ -4823,7 +5335,7 @@
"mock",
"xunit"
],
"time": "2014-09-10 14:10:18"
"time": "2014-10-04 10:04:20"
},
{
"name": "sebastian/comparator",
@ -4948,24 +5460,24 @@
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/environment.git",
"reference": "10c7467da0622f7848cc5cadc0828c3359254df4"
"reference": "6288ebbf6fa3ed2b2ff2d69c356fbaaf4f0971a7"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/10c7467da0622f7848cc5cadc0828c3359254df4",
"reference": "10c7467da0622f7848cc5cadc0828c3359254df4",
"url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/6288ebbf6fa3ed2b2ff2d69c356fbaaf4f0971a7",
"reference": "6288ebbf6fa3ed2b2ff2d69c356fbaaf4f0971a7",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"require-dev": {
"phpunit/phpunit": "~4.0"
"phpunit/phpunit": "~4.3"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
"dev-master": "1.1.x-dev"
}
},
"autoload": {
@ -4980,8 +5492,7 @@
"authors": [
{
"name": "Sebastian Bergmann",
"email": "sebastian@phpunit.de",
"role": "lead"
"email": "sebastian@phpunit.de"
}
],
"description": "Provides functionality to handle HHVM/PHP environments",
@ -4991,7 +5502,7 @@
"environment",
"hhvm"
],
"time": "2014-05-04 17:56:05"
"time": "2014-10-07 09:23:16"
},
{
"name": "sebastian/exporter",
@ -5064,12 +5575,12 @@
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/global-state.git",
"reference": "cd2f406aa90b591e1c45023c3a8d77edcb417bac"
"reference": "231d48620efde984fd077ee92916099a3ece9a59"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/cd2f406aa90b591e1c45023c3a8d77edcb417bac",
"reference": "cd2f406aa90b591e1c45023c3a8d77edcb417bac",
"url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/231d48620efde984fd077ee92916099a3ece9a59",
"reference": "231d48620efde984fd077ee92916099a3ece9a59",
"shasum": ""
},
"require": {
@ -5107,7 +5618,7 @@
"keywords": [
"global state"
],
"time": "2014-09-04 07:21:11"
"time": "2014-10-06 09:49:11"
},
{
"name": "sebastian/version",
@ -5151,12 +5662,12 @@
"source": {
"type": "git",
"url": "https://github.com/symfony/Yaml.git",
"reference": "6644c5c6b395e63a55186dea1817eed0ceb1c075"
"reference": "499f7d7aa96747ad97940089bd7a1fb24ad8182a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/Yaml/zipball/6644c5c6b395e63a55186dea1817eed0ceb1c075",
"reference": "6644c5c6b395e63a55186dea1817eed0ceb1c075",
"url": "https://api.github.com/repos/symfony/Yaml/zipball/499f7d7aa96747ad97940089bd7a1fb24ad8182a",
"reference": "499f7d7aa96747ad97940089bd7a1fb24ad8182a",
"shasum": ""
},
"require": {
@ -5189,7 +5700,7 @@
],
"description": "Symfony Yaml Component",
"homepage": "http://symfony.com",
"time": "2014-09-22 11:59:59"
"time": "2014-10-05 13:53:50"
}
],
"aliases": [