From 44d518e95a49fc24cf51b6193f97f3b6c08b3c80 Mon Sep 17 00:00:00 2001 From: DavidBadura Date: Tue, 7 Jul 2015 23:17:00 +0000 Subject: [PATCH 1/3] fist draft --- composer.json | 3 +- src/Exception/ReferenceException.php | 12 +++ src/Serializer/Handler/DependsHandler.php | 101 ++++++++++++++++++++++ src/Task.php | 33 +++++++ src/TaskManager.php | 49 +++++++++++ src/Taskwarrior.php | 8 ++ tests/TaskManagerTest.php | 55 ++++++++++++ 7 files changed, 260 insertions(+), 1 deletion(-) create mode 100644 src/Exception/ReferenceException.php create mode 100644 src/Serializer/Handler/DependsHandler.php diff --git a/composer.json b/composer.json index f08e741..1e1e6bd 100644 --- a/composer.json +++ b/composer.json @@ -23,7 +23,8 @@ "nesbot/carbon": "^1.14", "doctrine/collections": "^1.3", "webmozart/path-util": "^2.0", - "webmozart/assert": "^1.0.1" + "webmozart/assert": "^1.0.1", + "ocramius/proxy-manager": "^1.0" }, "require-dev": { "phpunit/phpunit": "^4.0", diff --git a/src/Exception/ReferenceException.php b/src/Exception/ReferenceException.php new file mode 100644 index 0000000..ed6f36a --- /dev/null +++ b/src/Exception/ReferenceException.php @@ -0,0 +1,12 @@ + + */ +class DependsHandler implements SubscribingHandlerInterface +{ + /** + * @var TaskManager + */ + protected $taskManager; + + /** + * @param TaskManager $taskManager + */ + function __construct(TaskManager $taskManager) + { + $this->taskManager = $taskManager; + } + + /** + * @return array + */ + public static function getSubscribingMethods() + { + $methods = array(); + + $methods[] = array( + 'type' => 'Depends', + 'format' => 'json', + 'direction' => GraphNavigator::DIRECTION_DESERIALIZATION, + 'method' => 'deserializeCarbon' + ); + + $methods[] = array( + 'type' => 'Depends', + 'format' => 'json', + 'direction' => GraphNavigator::DIRECTION_SERIALIZATION, + 'method' => 'serializeCarbon' + ); + + return $methods; + } + + /** + * @param VisitorInterface $visitor + * @param Task[] $tasks + * @param array $type + * @param Context $context + * @return string + * @throws ReferenceException + */ + public function serializeCarbon(VisitorInterface $visitor, $tasks, array $type, Context $context) + { + $list = []; + + foreach ($tasks as $task) { + if (!$task->getUuid()) { + throw new ReferenceException("you can't save a task that has dependencies to tasks that have not been saved"); + } + + $list[] = $task->getUuid(); + } + + return $visitor->visitString(implode(',', $list), $type, $context); + } + + /** + * @param VisitorInterface $visitor + * @param string $data + * @param array $type + * @return ArrayCollection + */ + public function deserializeCarbon(VisitorInterface $visitor, $data, array $type) + { + dump($data); + + if (!$data) { + return new ArrayCollection(); + } + + $tasks = []; + + foreach (explode(',', $data) as $uuid) { + $tasks[] = $this->taskManager->getReference($uuid); + } + + return new ArrayCollection($tasks); + } +} diff --git a/src/Task.php b/src/Task.php index b6a265d..c95a92f 100644 --- a/src/Task.php +++ b/src/Task.php @@ -4,6 +4,7 @@ namespace DavidBadura\Taskwarrior; use Carbon\Carbon; use DavidBadura\Taskwarrior\Exception\DatetimeParseException; +use Doctrine\Common\Collections\ArrayCollection; use JMS\Serializer\Annotation as JMS; /** @@ -126,6 +127,13 @@ class Task */ private $status; + /** + * @var Task[]|ArrayCollection + * + * @JMS\Type("Depends") + */ + private $depends; + /** * */ @@ -134,6 +142,7 @@ class Task $this->urgency = 0; $this->entry = new Carbon('now'); $this->status = self::STATUS_PENDING; + $this->depends = new ArrayCollection(); } /** @@ -268,6 +277,30 @@ class Task } } + /** + * @return Task[]|ArrayCollection + */ + public function getDependencies() + { + return $this->depends; + } + + /** + * @param Task $task + */ + public function addDependency(Task $task) + { + $this->depends->add($task); + } + + /** + * @param Task $task + */ + public function removeDependency(Task $task) + { + $this->depends->removeElement($task); + } + /** * @return Recurring */ diff --git a/src/TaskManager.php b/src/TaskManager.php index 8379c2a..31ff42c 100644 --- a/src/TaskManager.php +++ b/src/TaskManager.php @@ -4,10 +4,13 @@ namespace DavidBadura\Taskwarrior; use DavidBadura\Taskwarrior\Config\Context; use DavidBadura\Taskwarrior\Config\Report; +use DavidBadura\Taskwarrior\Exception\ReferenceException; use DavidBadura\Taskwarrior\Exception\TaskwarriorException; use DavidBadura\Taskwarrior\Query\QueryBuilder; use DavidBadura\Taskwarrior\Serializer\Handler\CarbonHandler; +use DavidBadura\Taskwarrior\Serializer\Handler\DependsHandler; use DavidBadura\Taskwarrior\Serializer\Handler\RecurringHandler; +use DavidBadura\Taskwarrior\Serializer\Handler\TaskHandler; use Doctrine\Common\Collections\ArrayCollection; use JMS\Serializer\Handler\HandlerRegistryInterface; use JMS\Serializer\JsonSerializationVisitor; @@ -15,6 +18,9 @@ use JMS\Serializer\Naming\CamelCaseNamingStrategy; use JMS\Serializer\Naming\SerializedNameAnnotationStrategy; use JMS\Serializer\Serializer; use JMS\Serializer\SerializerBuilder; +use ProxyManager\Factory\LazyLoadingGhostFactory; +use ProxyManager\Factory\LazyLoadingValueHolderFactory; +use ProxyManager\Proxy\LazyLoadingInterface; /** * @author David Badura @@ -285,6 +291,38 @@ class TaskManager ->getResult(); } + /** + * @param string $uuid + * @return Task + */ + public function getReference($uuid) + { + if (isset($this->tasks[$uuid])) { + return $this->tasks[$uuid]; + } + + $self = $this; + $factory = new LazyLoadingValueHolderFactory(); + + $initializer = function ( + & $wrappedObject, + LazyLoadingInterface $proxy, + $method, + array $parameters, + & $initializer + ) use ($self, $uuid) { + + $initializer = null; + $wrappedObject = $this->export($uuid)[0]; + + return true; + }; + + $task = $factory->createProxy('DavidBadura\Taskwarrior\Task', $initializer); + + return $this->tasks[$uuid] = $task; + } + /** * @param Task $task */ @@ -338,6 +376,16 @@ class TaskManager $params['recur'] = $task->getRecurring()->getValue(); } + $params['depends'] = []; + + foreach ($task->getDependencies() as $depend) { + if (!$depend->getUuid()) { + throw new ReferenceException("you can't save a task that has dependencies to tasks that have not been saved"); + } + + $params['depends'][] = $depend->getUuid(); + } + $this->taskwarrior->modify($params, $task->getUuid()); } @@ -419,6 +467,7 @@ class TaskManager ->configureHandlers(function (HandlerRegistryInterface $registry) { $registry->registerSubscribingHandler(new CarbonHandler()); $registry->registerSubscribingHandler(new RecurringHandler()); + $registry->registerSubscribingHandler(new DependsHandler($this)); }) ->addDefaultHandlers() ->setSerializationVisitor('json', $visitor) diff --git a/src/Taskwarrior.php b/src/Taskwarrior.php index 0de5b32..d8ae36b 100644 --- a/src/Taskwarrior.php +++ b/src/Taskwarrior.php @@ -309,6 +309,14 @@ class Taskwarrior } } + if (array_key_exists('depends', $params)) { + if (is_array($params['depends'])) { + $options[] = 'depends:' . implode(',', $params['depends']); + } else { + $options[] = 'depends:' . $params['depends']; + } + } + if (array_key_exists('status', $params)) { $options[] = 'status:' . $params['status']; } diff --git a/tests/TaskManagerTest.php b/tests/TaskManagerTest.php index 740770a..4e17610 100644 --- a/tests/TaskManagerTest.php +++ b/tests/TaskManagerTest.php @@ -787,6 +787,61 @@ class TaskManagerTest extends \PHPUnit_Framework_TestCase $this->assertCount(1, $this->taskManager->filterPending('(status:pending or status:waiting)')); } + public function testDependenciesException() + { + $this->setExpectedException('DavidBadura\Taskwarrior\Exception\ReferenceException'); + + $task1 = new Task(); + $task1->setDescription("a"); + + $task2 = new Task(); + $task2->setDescription("b"); + + $task3 = new Task(); + $task3->setDescription("c"); + + $task1->addDependency($task2); + $task1->addDependency($task3); + + $this->taskManager->save($task1); + } + + + public function testDependencies() + { + $task1 = new Task(); + $task1->setDescription("a"); + + $task2 = new Task(); + $task2->setDescription("b"); + + $task1->addDependency($task2); + + $this->taskManager->save($task2); + $this->taskManager->save($task1); + + $this->taskManager->clear(); + $temp1 = $this->taskManager->find($task1->getUuid()); + + $this->assertCount(1, $temp1->getDependencies()); + + $temp2 = $temp1->getDependencies()[0]; + + $this->assertInstanceOf('DavidBadura\Taskwarrior\Task', $temp2); + $this->assertEquals('b', $temp2->getDescription()); + + $temp1->removeDependency($temp2); + + $this->taskManager->save($temp1); + + $this->taskManager->clear(); + $temp1 = $this->taskManager->find($task1->getUuid()); + + dump($temp1); + + $this->assertCount(0, $temp1->getDependencies()); + } + /** * @param string $string * @return \DateTime From 2dbcb2ca6af80e79de0310eadaf9efed9baa52ab Mon Sep 17 00:00:00 2001 From: DavidBadura Date: Wed, 8 Jul 2015 11:55:42 +0200 Subject: [PATCH 2/3] fix tests --- src/Exception/ReferenceException.php | 10 ++++------ src/Serializer/Handler/DependsHandler.php | 10 ++++------ src/Task.php | 14 +++++++++++++- src/TaskManager.php | 14 ++++++++++++-- tests/TaskManagerTest.php | 4 +--- 5 files changed, 34 insertions(+), 18 deletions(-) diff --git a/src/Exception/ReferenceException.php b/src/Exception/ReferenceException.php index ed6f36a..a72e981 100644 --- a/src/Exception/ReferenceException.php +++ b/src/Exception/ReferenceException.php @@ -1,12 +1,10 @@ + */ class ReferenceException extends TaskwarriorException { - -} \ No newline at end of file +} diff --git a/src/Serializer/Handler/DependsHandler.php b/src/Serializer/Handler/DependsHandler.php index 997c026..fbda42d 100644 --- a/src/Serializer/Handler/DependsHandler.php +++ b/src/Serializer/Handler/DependsHandler.php @@ -40,14 +40,14 @@ class DependsHandler implements SubscribingHandlerInterface 'type' => 'Depends', 'format' => 'json', 'direction' => GraphNavigator::DIRECTION_DESERIALIZATION, - 'method' => 'deserializeCarbon' + 'method' => 'deserialize' ); $methods[] = array( 'type' => 'Depends', 'format' => 'json', 'direction' => GraphNavigator::DIRECTION_SERIALIZATION, - 'method' => 'serializeCarbon' + 'method' => 'serialize' ); return $methods; @@ -61,7 +61,7 @@ class DependsHandler implements SubscribingHandlerInterface * @return string * @throws ReferenceException */ - public function serializeCarbon(VisitorInterface $visitor, $tasks, array $type, Context $context) + public function serialize(VisitorInterface $visitor, $tasks, array $type, Context $context) { $list = []; @@ -82,10 +82,8 @@ class DependsHandler implements SubscribingHandlerInterface * @param array $type * @return ArrayCollection */ - public function deserializeCarbon(VisitorInterface $visitor, $data, array $type) + public function deserialize(VisitorInterface $visitor, $data, array $type) { - dump($data); - if (!$data) { return new ArrayCollection(); } diff --git a/src/Task.php b/src/Task.php index c95a92f..adcc979 100644 --- a/src/Task.php +++ b/src/Task.php @@ -301,6 +301,18 @@ class Task $this->depends->removeElement($task); } + /** + * @param Task[] $tasks + */ + public function setDependencies(array $tasks) + { + $this->depends = new ArrayCollection(); + + foreach ($tasks as $task) { + $this->addDependency($task); + } + } + /** * @return Recurring */ @@ -462,4 +474,4 @@ class Task $this->entry = new Carbon('now'); $this->status = self::STATUS_PENDING; } -} \ No newline at end of file +} diff --git a/src/TaskManager.php b/src/TaskManager.php index 31ff42c..e0b798c 100644 --- a/src/TaskManager.php +++ b/src/TaskManager.php @@ -340,7 +340,17 @@ class TaskManager { $json = $this->taskwarrior->export($filter); - return $this->getSerializer()->deserialize($json, 'array', 'json'); + $tasks = $this->getSerializer()->deserialize($json, 'array', 'json'); + + foreach ($tasks as $task) { + if ($task->getDependencies()) { + continue; + } + + $task->setDependencies(array()); + } + + return $tasks; } /** @@ -482,4 +492,4 @@ class TaskManager { return new self(new Taskwarrior()); } -} \ No newline at end of file +} diff --git a/tests/TaskManagerTest.php b/tests/TaskManagerTest.php index 4e17610..6955328 100644 --- a/tests/TaskManagerTest.php +++ b/tests/TaskManagerTest.php @@ -837,8 +837,6 @@ class TaskManagerTest extends \PHPUnit_Framework_TestCase $this->taskManager->clear(); $temp1 = $this->taskManager->find($task1->getUuid()); - dump($temp1); - $this->assertCount(0, $temp1->getDependencies()); } @@ -850,4 +848,4 @@ class TaskManagerTest extends \PHPUnit_Framework_TestCase { return new \Carbon\Carbon($string); } -} \ No newline at end of file +} From 15300db995e87eff5e989b7ce8aebbbc093f5650 Mon Sep 17 00:00:00 2001 From: DavidBadura Date: Wed, 8 Jul 2015 13:41:05 +0200 Subject: [PATCH 3/3] update readme --- README.md | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/README.md b/README.md index b089539..e3d05c9 100644 --- a/README.md +++ b/README.md @@ -157,6 +157,28 @@ reopen task: $tm->reopen($task); ``` +dependencies: + +```php +$task1 = new Task(); +$task1->setDescription('a'); + +$task2 = new Task(); +$task2->setDescription('b'); + +$task1->addDependency($task2); + +// the order is important! +$tm->save($task2); +$tm->save($task1); + +$tm->clear(); // clear object cache + +$task1 = $tm->find('uuid-from-task1'); +$task2 = $task1->getDependencies()[0]; +echo $task2->getDesciption(); // "b" <- lazy loading +``` + ### QueryBuilder example: