diff --git a/src/Task.php b/src/Task.php index 4d92cff..38ca52d 100644 --- a/src/Task.php +++ b/src/Task.php @@ -53,6 +53,20 @@ class Task */ private $due; + /** + * @var \DateTime + * + * @JMS\Type(name="DateTime<'Ymd\THis\Z'>") + */ + private $wait; + + /** + * @var \DateTime + * + * @JMS\Type(name="DateTime<'Ymd\THis\Z'>") + */ + private $until; + /** * @var array * @@ -74,6 +88,21 @@ class Task */ private $entry; + + /** + * @var \DateTime + * + * @JMS\Type(name="DateTime<'Ymd\THis\Z'>") + */ + private $modified; + + /** + * @var \DateTime + * + * @JMS\Type(name="DateTime<'Ymd\THis\Z'>") + */ + private $end; + /** * @var string * @@ -156,11 +185,43 @@ class Task } /** - * @param \DateTime $due + * @param \DateTime|string $due */ - public function setDue(\DateTime $due = null) + public function setDue($due = null) { - $this->due = $due; + $this->due = $this->parseDateTime($due); + } + + /** + * @return \DateTime + */ + public function getWait() + { + return $this->wait; + } + + /** + * @param \DateTime|string $wait + */ + public function setWait($wait = null) + { + $this->wait = $this->parseDateTime($wait); + } + + /** + * @return \DateTime + */ + public function getUntil() + { + return $this->until; + } + + /** + * @param \DateTime|string $until + */ + public function setUntil($until = null) + { + $this->until = $this->parseDateTime($until); } /** @@ -215,6 +276,22 @@ class Task return $this->entry; } + /** + * @return \DateTime + */ + public function getModified() + { + return $this->modified; + } + + /** + * @return \DateTime + */ + public function getEnd() + { + return $this->end; + } + /** * @return float */ @@ -263,6 +340,32 @@ class Task return $this->status == self::STATUS_DELETED; } + /** + * @param string|\DateTime|null $date + * @return \DateTime|null + * @throws TaskwarriorException + */ + private function parseDateTime($date) + { + if ($date instanceof \DateTime) { + + $date = clone $date; + $date->setTimezone(new \DateTimeZone('UTC')); + + return $date; + } + + if (is_string($date)) { + return new \DateTime($date, new \DateTimeZone('UTC')); + } + + if ($date === null) { + return null; + } + + throw new TaskwarriorException(); + } + /** * */ diff --git a/src/TaskManager.php b/src/TaskManager.php index f8a0281..a0a8e4b 100644 --- a/src/TaskManager.php +++ b/src/TaskManager.php @@ -47,6 +47,8 @@ class TaskManager } else { $this->edit($task); } + + $this->refresh($task); } /** @@ -89,6 +91,7 @@ class TaskManager if (isset($this->tasks[$task->getUuid()])) { $result[$key] = $this->tasks[$task->getUuid()]; + $this->merge($result[$key], $task); continue; } @@ -120,7 +123,7 @@ class TaskManager } $this->taskwarrior->delete($task->getUuid()); - $this->update($task); + $this->refresh($task); } /** @@ -133,15 +136,16 @@ class TaskManager } $this->taskwarrior->done($task->getUuid()); - $this->update($task); + $this->refresh($task); } /** - * @return array + * @param Task $task */ - public function projects() + public function refresh(Task $task) { - return $this->taskwarrior->projects(); + $clean = $this->export($task->getUuid())[0]; + $this->merge($task, $clean); } /** @@ -178,8 +182,6 @@ class TaskManager $this->setValue($task, 'uuid', $uuid); $this->tasks[$uuid] = $task; - - $this->update($task); } /** @@ -194,22 +196,22 @@ class TaskManager 'priority' => $task->getPriority(), 'tags' => $task->getTags(), 'due' => $task->getDue() ? $task->getDue()->format('Ymd\THis\Z') : null, + 'wait' => $task->getWait() ? $task->getWait()->format('Ymd\THis\Z') : null, ], $task->getUuid() ); - - $this->update($task); } /** - * @param Task $task + * @param Task $old + * @param Task $new */ - private function update(Task $task) + private function merge(Task $old, Task $new) { - $clean = $this->export($task->getUuid())[0]; - - $this->setValue($task, 'urgency', $clean->getUrgency()); - $this->setValue($task, 'status', $clean->getStatus()); + $this->setValue($old, 'urgency', $new->getUrgency()); + $this->setValue($old, 'status', $new->getStatus()); + $this->setValue($old, 'modified', $new->getModified()); + $this->setValue($old, 'end', $new->getEnd()); } /** @@ -249,9 +251,9 @@ class TaskManager } /** - * @param Task $task + * @param Task $task * @param string $attr - * @param mixed $value + * @param mixed $value */ private function setValue(Task $task, $attr, $value) { diff --git a/src/Taskwarrior.php b/src/Taskwarrior.php index 943104e..cf12499 100644 --- a/src/Taskwarrior.php +++ b/src/Taskwarrior.php @@ -19,7 +19,7 @@ class Taskwarrior /** * @param string $taskrc * @param string $taskData - * @param array $rcOptions + * @param array $rcOptions */ public function __construct($taskrc = '~/.taskrc', $taskData = '~/.task', $rcOptions = []) { @@ -52,52 +52,48 @@ class Taskwarrior /** * @param array $params - * @param string|array $filter + * @throws TaskwarriorException */ - public function modify(array $params, $filter = null) + public function add(array $params) { - $options = []; - - if (array_key_exists('due', $params)) { - $options[] = 'due:' . $params['due']; - } - - if (array_key_exists('project', $params)) { - $options[] = 'project:' . $params['project']; - } - - if (array_key_exists('priority', $params)) { - $options[] = 'priority:' . $params['priority']; - } - - if (array_key_exists('tags', $params)) { - if (is_array($params['tags'])) { - $options[] = 'tags:' . implode(',', $params['tags']); - } else { - $options[] = 'tags:' . $params['tags']; - } - } - - if (array_key_exists('description', $params)) { - $options[] = $params['description']; - } - - $this->command('modify', $filter, $options); + $this->command('modify', null, $this->getOptions($params)); } /** + * @param array $params + * @param string|array $filter + */ + public function modify(array $params, $filter = null) + { + $this->command('modify', $filter, $this->getOptions($params)); + } + + /** + * @param null $filter * @return array * @throws TaskwarriorException */ - public function projects() + public function projects($filter = null) { - $result = $this->command('_project'); + $result = $this->command('_project', $filter); return array_filter(explode("\n", $result), 'strlen'); } /** - * @param string $json + * @param null $filter + * @return array + * @throws TaskwarriorException + */ + public function tags($filter = null) + { + $result = $this->command('_tags', $filter); + + return array_filter(explode("\n", $result), 'strlen'); + } + + /** + * @param string $json * @return string * @throws TaskwarriorException */ @@ -112,11 +108,11 @@ class Taskwarrior $fs->remove($file); - if (!preg_match('/([0-9a-f]{8}\-[0-9a-f]{4}\-[0-9a-f]{4}\-[0-9a-f]{4}\-[0-9a-f]{12})/', $output, $matches)) { - throw new TaskwarriorException(); + if ($uuid = self::parseUuid($output)) { + return $uuid; } - return $matches[1]; + throw new TaskwarriorException(); } /** @@ -129,9 +125,9 @@ class Taskwarrior } /** - * @param string $command + * @param string $command * @param string|array $filter - * @param array $options + * @param array $options * @return string * @throws TaskwarriorException */ @@ -140,7 +136,7 @@ class Taskwarrior $builder = $this->createProcessBuilder(); if (!is_array($filter)) { - $filter = [$filter]; + $filter = explode(' ', $filter); } foreach ($filter as $param) { @@ -180,6 +176,49 @@ class Taskwarrior return $this->command('_version'); } + /** + * @param $params + * @return array + */ + private function getOptions($params) + { + $options = []; + + if (array_key_exists('due', $params)) { + $options[] = 'due:' . $params['due']; + } + + if (array_key_exists('wait', $params)) { + $options[] = 'wait:' . $params['wait']; + } + + if (array_key_exists('until', $params)) { + $options[] = 'until:' . $params['until']; + } + + if (array_key_exists('project', $params)) { + $options[] = 'project:' . $params['project']; + } + + if (array_key_exists('priority', $params)) { + $options[] = 'priority:' . $params['priority']; + } + + if (array_key_exists('tags', $params)) { + if (is_array($params['tags'])) { + $options[] = 'tags:' . implode(',', $params['tags']); + } else { + $options[] = 'tags:' . $params['tags']; + } + } + + if (array_key_exists('description', $params)) { + $options[] = $params['description']; + } + + return $options; + } + /** * @return ProcessBuilder */ @@ -196,4 +235,17 @@ class Taskwarrior return $builder; } + + /** + * @param string $string + * @return string|null + */ + public static function parseUuid($string) + { + if (preg_match('/([0-9a-f]{8}\-[0-9a-f]{4}\-[0-9a-f]{4}\-[0-9a-f]{4}\-[0-9a-f]{12})/', $string, $matches)) { + return $matches[1]; + } + + return null; + } } \ No newline at end of file diff --git a/tests/TaskManagerTest.php b/tests/TaskManagerTest.php index 2fa1db4..04cc12f 100644 --- a/tests/TaskManagerTest.php +++ b/tests/TaskManagerTest.php @@ -176,6 +176,32 @@ class TaskManagerTest extends \PHPUnit_Framework_TestCase $this->assertCount(1, $this->taskManager->filter('project:home prio:H +now')); } + public function testDates() + { + $task1 = new Task(); + $task1->setDescription('foo1'); + + $this->taskManager->save($task1); + + $this->assertInstanceOf('DateTime', $task1->getEntry()); + $this->assertNull($task1->getModified()); + $this->assertNull($task1->getEnd()); + + $task1->setDescription('bar2'); + + $this->taskManager->save($task1); + + $this->assertInstanceOf('DateTime', $task1->getEntry()); + $this->assertInstanceOf('DateTime', $task1->getModified()); + $this->assertNull($task1->getEnd()); + + $this->taskManager->done($task1); + + $this->assertInstanceOf('DateTime', $task1->getEntry()); + $this->assertInstanceOf('DateTime', $task1->getModified()); + $this->assertInstanceOf('DateTime', $task1->getEnd()); + } + public function testPending() { $task1 = new Task(); @@ -377,7 +403,7 @@ class TaskManagerTest extends \PHPUnit_Framework_TestCase $this->taskManager->save($task1); $this->taskManager->save($task2); - $this->assertEquals(array('home', 'office'), $this->taskManager->projects()); + $this->assertEquals(array('home', 'office'), $this->taskwarrior->projects()); } public function testPriority() @@ -434,6 +460,46 @@ class TaskManagerTest extends \PHPUnit_Framework_TestCase $this->assertCount(1, $this->taskManager->filter('+b')); } + public function testWait() + { + $task1 = new Task(); + $task1->setDescription('foo1'); + + $this->taskManager->save($task1); + $this->taskManager->clear(); + + $task1 = $this->taskManager->find($task1->getUuid()); + $this->assertNull($task1->getWait()); + + $task1->setWait($this->createDateTime('+2 sec')); + $this->taskManager->save($task1); + $this->assertTrue($task1->isWaiting()); + + $this->assertCount(0, $this->taskManager->filter()); + $this->assertCount(1, $this->taskManager->filterAll('status:waiting')); + + sleep(3); + + $this->assertCount(1, $this->taskManager->filter()); + $this->assertFalse($task1->isWaiting()); + } + + public function testUntil() + { + $this->markTestIncomplete('not working yet'); + + $task1 = new Task(); + $task1->setDescription('foo1'); + $task1->setUntil('+2 sec'); + + $this->taskManager->save($task1); + + $this->assertCount(1, $this->taskManager->filter()); + + sleep(3); + + $this->assertCount(0, $this->taskManager->filter()); + } /** * @param string $string @@ -441,6 +507,6 @@ class TaskManagerTest extends \PHPUnit_Framework_TestCase */ private function createDateTime($string = 'now') { - return new \DateTime($string, new \DateTimeZone('UTC')); + return new \DateTime($string); } } \ No newline at end of file