optimize proxy implementation

This commit is contained in:
DavidBadura 2015-07-08 23:29:50 +00:00
parent 79e63251f4
commit 95870fc7a2
4 changed files with 162 additions and 35 deletions

View File

@ -0,0 +1,30 @@
<?php
namespace DavidBadura\Taskwarrior\Proxy;
/**
* @author David Badura <d.a.badura@gmail.com>
*/
class UuidContainer
{
/**
* @var string
*/
protected $uuid;
/**
* @param string $uuid
*/
public function __construct($uuid)
{
$this->uuid = $uuid;
}
/**
* @return string
*/
public function getUuid()
{
return $this->uuid;
}
}

View File

@ -304,7 +304,7 @@ class Task
/** /**
* @param Task[] $tasks * @param Task[] $tasks
*/ */
public function setDependencies(array $tasks) public function setDependencies(array $tasks = [])
{ {
$this->depends = new ArrayCollection(); $this->depends = new ArrayCollection();

View File

@ -6,11 +6,11 @@ use DavidBadura\Taskwarrior\Config\Context;
use DavidBadura\Taskwarrior\Config\Report; use DavidBadura\Taskwarrior\Config\Report;
use DavidBadura\Taskwarrior\Exception\ReferenceException; use DavidBadura\Taskwarrior\Exception\ReferenceException;
use DavidBadura\Taskwarrior\Exception\TaskwarriorException; use DavidBadura\Taskwarrior\Exception\TaskwarriorException;
use DavidBadura\Taskwarrior\Proxy\UuidContainer;
use DavidBadura\Taskwarrior\Query\QueryBuilder; use DavidBadura\Taskwarrior\Query\QueryBuilder;
use DavidBadura\Taskwarrior\Serializer\Handler\CarbonHandler; use DavidBadura\Taskwarrior\Serializer\Handler\CarbonHandler;
use DavidBadura\Taskwarrior\Serializer\Handler\DependsHandler; use DavidBadura\Taskwarrior\Serializer\Handler\DependsHandler;
use DavidBadura\Taskwarrior\Serializer\Handler\RecurringHandler; use DavidBadura\Taskwarrior\Serializer\Handler\RecurringHandler;
use DavidBadura\Taskwarrior\Serializer\Handler\TaskHandler;
use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\ArrayCollection;
use JMS\Serializer\Handler\HandlerRegistryInterface; use JMS\Serializer\Handler\HandlerRegistryInterface;
use JMS\Serializer\JsonSerializationVisitor; use JMS\Serializer\JsonSerializationVisitor;
@ -18,9 +18,9 @@ use JMS\Serializer\Naming\CamelCaseNamingStrategy;
use JMS\Serializer\Naming\SerializedNameAnnotationStrategy; use JMS\Serializer\Naming\SerializedNameAnnotationStrategy;
use JMS\Serializer\Serializer; use JMS\Serializer\Serializer;
use JMS\Serializer\SerializerBuilder; use JMS\Serializer\SerializerBuilder;
use ProxyManager\Factory\LazyLoadingGhostFactory;
use ProxyManager\Factory\LazyLoadingValueHolderFactory; use ProxyManager\Factory\LazyLoadingValueHolderFactory;
use ProxyManager\Proxy\LazyLoadingInterface; use ProxyManager\Proxy\LazyLoadingInterface;
use ProxyManager\Proxy\ValueHolderInterface;
/** /**
* @author David Badura <d.a.badura@gmail.com> * @author David Badura <d.a.badura@gmail.com>
@ -92,17 +92,9 @@ class TaskManager
return $this->tasks[$uuid]; return $this->tasks[$uuid];
} }
$tasks = $this->filter($uuid); $task = $this->exportOne($uuid);
if (count($tasks) == 0) { return $this->tasks[$uuid] = $task;
return null;
}
if (count($tasks) == 1) {
return $tasks[0];
}
throw new TaskwarriorException();
} }
/** /**
@ -114,15 +106,34 @@ class TaskManager
$result = $this->export($filter); $result = $this->export($filter);
foreach ($result as $key => $task) { foreach ($result as $key => $task) {
if (isset($this->tasks[$task->getUuid()])) {
$result[$key] = $this->tasks[$task->getUuid()]; // not yet known? then remember it
$this->merge($result[$key], $task); if (!isset($this->tasks[$task->getUuid()])) {
$this->tasks[$task->getUuid()] = $task;
continue; continue;
} }
$this->tasks[$task->getUuid()] = $task; // replace result entry
$result[$key] = $prev = $this->tasks[$task->getUuid()];
// not proxy? update task
if (!$prev instanceof LazyLoadingInterface || !$prev instanceof ValueHolderInterface) {
$this->merge($prev, $task);
continue;
}
// wrapper object is a task? skip
if ($prev->getWrappedValueHolderValue() instanceof Task) {
continue;
}
// replace proxy initializer
$prev->setProxyInitializer(function (&$wrappedObject, LazyLoadingInterface $proxy) use ($task) {
$proxy->setProxyInitializer(null);
$wrappedObject = $task;
});
} }
return new ArrayCollection($result); return new ArrayCollection($result);
@ -301,21 +312,21 @@ class TaskManager
return $this->tasks[$uuid]; return $this->tasks[$uuid];
} }
$self = $this;
$factory = new LazyLoadingValueHolderFactory(); $factory = new LazyLoadingValueHolderFactory();
$initializer = function ( $initializer = function (
& $wrappedObject, &$wrappedObject,
LazyLoadingInterface $proxy, LazyLoadingInterface $proxy,
$method, $method
array $parameters, ) use ($uuid) {
& $initializer if ('getUuid' == $method) {
) use ($self, $uuid) { if (!$wrappedObject) {
$wrappedObject = new UuidContainer($uuid);
$initializer = null; }
$wrappedObject = $this->export($uuid)[0]; } else {
$proxy->setProxyInitializer(null);
return true; $wrappedObject = $this->exportOne($uuid);
}
}; };
$task = $factory->createProxy('DavidBadura\Taskwarrior\Task', $initializer); $task = $factory->createProxy('DavidBadura\Taskwarrior\Task', $initializer);
@ -328,7 +339,12 @@ class TaskManager
*/ */
private function refresh(Task $task) private function refresh(Task $task)
{ {
$clean = $this->export($task->getUuid())[0]; // skip refresh & initailize task
if ($task instanceof LazyLoadingInterface && !$task->isProxyInitialized()) {
return;
}
$clean = $this->exportOne($task->getUuid());
$this->merge($task, $clean); $this->merge($task, $clean);
} }
@ -340,19 +356,38 @@ class TaskManager
{ {
$json = $this->taskwarrior->export($filter); $json = $this->taskwarrior->export($filter);
/** @var Task[] $tasks */
$tasks = $this->getSerializer()->deserialize($json, 'array<DavidBadura\Taskwarrior\Task>', 'json'); $tasks = $this->getSerializer()->deserialize($json, 'array<DavidBadura\Taskwarrior\Task>', 'json');
foreach ($tasks as $task) { foreach ($tasks as $task) {
if ($task->getDependencies()) { if (!$task->getDependencies()) {
continue; $task->setDependencies([]);
} }
$task->setDependencies(array());
} }
return $tasks; return $tasks;
} }
/**
* @param string|array $filter
* @return Task
* @throws TaskwarriorException
*/
private function exportOne($filter)
{
$tasks = $this->export($filter);
if (count($tasks) == 0) {
throw new TaskwarriorException('task not found');
}
if (count($tasks) > 1) {
throw new TaskwarriorException('multiple task found');
}
return $tasks[0];
}
/** /**
* @param Task $task * @param Task $task
* @throws TaskwarriorException * @throws TaskwarriorException

View File

@ -138,8 +138,10 @@ class TaskManagerTest extends \PHPUnit_Framework_TestCase
public function testDontFind() public function testDontFind()
{ {
$this->setExpectedException('DavidBadura\Taskwarrior\Exception\TaskwarriorException',
"task not found");
$task = $this->taskManager->find('56464asd46s4adas54da6'); $task = $this->taskManager->find('56464asd46s4adas54da6');
$this->assertNull($task);
} }
public function testDoubleSave() public function testDoubleSave()
@ -806,7 +808,6 @@ class TaskManagerTest extends \PHPUnit_Framework_TestCase
$this->taskManager->save($task1); $this->taskManager->save($task1);
} }
public function testDependencies() public function testDependencies()
{ {
$task1 = new Task(); $task1 = new Task();
@ -828,6 +829,7 @@ class TaskManagerTest extends \PHPUnit_Framework_TestCase
$temp2 = $temp1->getDependencies()[0]; $temp2 = $temp1->getDependencies()[0];
$this->assertInstanceOf('DavidBadura\Taskwarrior\Task', $temp2); $this->assertInstanceOf('DavidBadura\Taskwarrior\Task', $temp2);
$this->assertEquals($task2->getUuid(), $temp2->getUuid());
$this->assertEquals('b', $temp2->getDescription()); $this->assertEquals('b', $temp2->getDescription());
$temp1->removeDependency($temp2); $temp1->removeDependency($temp2);
@ -840,6 +842,66 @@ class TaskManagerTest extends \PHPUnit_Framework_TestCase
$this->assertCount(0, $temp1->getDependencies()); $this->assertCount(0, $temp1->getDependencies());
} }
public function testLazyReferencesUuid()
{
$task = $this->taskManager->getReference('foo');
$this->assertEquals('foo', $task->getUuid());
}
public function testLazyReferencesNotFound()
{
$this->setExpectedException('DavidBadura\Taskwarrior\Exception\TaskwarriorException');
$task = $this->taskManager->getReference('foo');
$task->getDescription();
}
public function testLazyReferencesLoad()
{
$task = new Task();
$task->setDescription('foo');
$this->taskManager->save($task);
$this->taskManager->clear();
$task2 = $this->taskManager->getReference($task->getUuid());
$this->assertNotSame($task, $task2);
$this->assertEquals('foo', $task2->getDescription());
}
public function testSameReferences()
{
$task = new Task();
$task->setDescription('foo');
$this->taskManager->save($task);
$task2 = $this->taskManager->getReference($task->getUuid());
$this->assertSame($task, $task2);
$this->assertEquals('foo', $task2->getDescription());
}
public function testFilterReferences()
{
$task = new Task();
$task->setDescription('foo');
$this->taskManager->save($task);
$this->taskManager->clear();
$task = $this->taskManager->getReference($task->getUuid());
$this->taskManager->filter();
$this->assertEquals('foo', $task->getDescription());
}
/** /**
* @param string $string * @param string $string
* @return \DateTime * @return \DateTime