From 70024c57fc9b6a7dbae7e6cef10a3862529c8b36 Mon Sep 17 00:00:00 2001 From: Steve Rayner Date: Tue, 29 Oct 2013 18:53:11 +0000 Subject: [PATCH 01/10] modified sql to be consistent with zfcUser --- data/schema.sql | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/data/schema.sql b/data/schema.sql index 6738b4d..8739383 100644 --- a/data/schema.sql +++ b/data/schema.sql @@ -1,20 +1,20 @@ CREATE TABLE discuss_thread ( - thread_id INTEGER PRIMARY KEY AUTO_INCREMENT NOT NULL, + thread_id INT UNSIGNED PRIMARY KEY AUTO_INCREMENT NOT NULL, subject VARCHAR(1000) NOT NULL, slug VARCHAR(255) NOT NULL ) ENGINE=InnoDB; CREATE TABLE discuss_message ( - message_id INTEGER PRIMARY KEY AUTO_INCREMENT NOT NULL, + message_id INT UNSIGNED PRIMARY KEY AUTO_INCREMENT NOT NULL, post_time DATETIME NOT NULL, - author_user_id INTEGER DEFAULT NULL, + author_user_id INT UNSIGNED DEFAULT NULL, author_email VARCHAR(255) DEFAULT NULL UNIQUE, author_name VARCHAR(50) DEFAULT NULL, - thread_id INTEGER NOT NULL, - parent_message_id INTEGER DEFAULT NULL, - subject VARCHAR(100) DEFAULT NOT NULL, + thread_id INT UNSIGNED NOT NULL, + parent_message_id INT UNSIGNED DEFAULT NULL, + subject VARCHAR(100) NOT NULL, message TEXT NOT NULL, FOREIGN KEY (author_user_id) REFERENCES user (user_id), FOREIGN KEY (thread_id) REFERENCES discuss_thread (thread_id) ON DELETE CASCADE, @@ -23,15 +23,15 @@ CREATE TABLE discuss_message CREATE TABLE discuss_tag ( - tag_id INTEGER PRIMARY KEY AUTO_INCREMENT NOT NULL, + tag_id INT UNSIGNED PRIMARY KEY AUTO_INCREMENT NOT NULL, name VARCHAR(255) NOT NULL, slug VARCHAR(255) NOT NULL ) ENGINE=InnoDB; CREATE TABLE discuss_thread_tag ( - thread_id INTEGER NOT NULL, - tag_id INTEGER DEFAULT NULL, + thread_id INT UNSIGNED NOT NULL, + tag_id INT UNSIGNED DEFAULT NULL, FOREIGN KEY (thread_id) REFERENCES discuss_thread (thread_id), FOREIGN KEY (tag_id) REFERENCES discuss_tag (tag_id) ) ENGINE=InnoDB; From ef582fce1e93a5d65610b4e9275f38962ddc70ab Mon Sep 17 00:00:00 2001 From: Steve Rayner Date: Mon, 4 Nov 2013 18:57:16 +0000 Subject: [PATCH 02/10] Added getTags method to discuss service and model. --- Module.php | 10 ++++ src/EdpDiscuss/Model/Tag/TagMapper.php | 12 ++++ .../Model/Tag/TagMapperInterface.php | 7 +++ src/EdpDiscuss/Service/Discuss.php | 10 ++++ src/EdpDiscuss/View/Helper/RenderForm.php | 55 +++++++++++++++++++ 5 files changed, 94 insertions(+) create mode 100644 src/EdpDiscuss/View/Helper/RenderForm.php diff --git a/Module.php b/Module.php index d74b6b7..b70e853 100644 --- a/Module.php +++ b/Module.php @@ -117,4 +117,14 @@ public static function getOption($option) } return static::$options[$option]; } + + public function getViewHelperConfig() + { + return array( + 'invokables' => array( + 'RenderForm' => 'EdpDiscuss\View\Helper\RenderForm' + ) + ); + + } } diff --git a/src/EdpDiscuss/Model/Tag/TagMapper.php b/src/EdpDiscuss/Model/Tag/TagMapper.php index f22b96b..d110e75 100644 --- a/src/EdpDiscuss/Model/Tag/TagMapper.php +++ b/src/EdpDiscuss/Model/Tag/TagMapper.php @@ -23,4 +23,16 @@ public function getTagById($tagId) return $this->select($select)->current(); } + + /** + * getTags + * + * @return array of TagInterface's + */ + public function getTags() + { + $select = $this->getSelect(); + $rowset = $this->select($select); + return $rowset; + } } diff --git a/src/EdpDiscuss/Model/Tag/TagMapperInterface.php b/src/EdpDiscuss/Model/Tag/TagMapperInterface.php index 0a3b91a..326bcf6 100644 --- a/src/EdpDiscuss/Model/Tag/TagMapperInterface.php +++ b/src/EdpDiscuss/Model/Tag/TagMapperInterface.php @@ -11,4 +11,11 @@ interface TagMapperInterface * @return TagInterface */ public function getTagById($tagId); + + /** + * getTags + * + * @return array of TagInterface's + */ + public function getTags(); } diff --git a/src/EdpDiscuss/Service/Discuss.php b/src/EdpDiscuss/Service/Discuss.php index 96b223b..74d3597 100644 --- a/src/EdpDiscuss/Service/Discuss.php +++ b/src/EdpDiscuss/Service/Discuss.php @@ -165,6 +165,16 @@ public function getTagById($tagId) { return $this->tagMapper->getTagById($tagId); } + + /** + * getTags + * + * @return array + */ + public function getTags() + { + return $this->tagMapper->getTags(); + } /** * getThreadById diff --git a/src/EdpDiscuss/View/Helper/RenderForm.php b/src/EdpDiscuss/View/Helper/RenderForm.php new file mode 100644 index 0000000..04d10f4 --- /dev/null +++ b/src/EdpDiscuss/View/Helper/RenderForm.php @@ -0,0 +1,55 @@ +prepare(); + + // Render the output. + $form->setAttribute('class', 'form-horizontal'); + $output = $this->view->form()->openTag($form) . PHP_EOL; + $elements = $form->getElements(); + foreach($elements as $element) + { + $hidden = ($element->getAttribute('type') == 'hidden'); + + if (!$hidden) + { + $messages = $element->getMessages(); + if (empty($messages)) { + $output .= '
' . PHP_EOL; + } else { + $output .= '
'; + } + } + + // Render label if present. + $label = $element->getLabel(); + if (isset($label) && '' !== $label) + { + $element->setLabelAttributes(array('class' => 'control-label')); + $output .= $this->view->formLabel($element) . PHP_EOL; + } + + // Render the actual element (and any errors) + $output .= '
' . PHP_EOL; + $output .= $this->view->formElement($element) . PHP_EOL; + $output .= $this->view->formElementErrors($element) . PHP_EOL; + $output .= '
' . PHP_EOL; + + if (!$hidden) + { + $output .= '
' . PHP_EOL; + } + } + $output .= $this->view->form()->closeTag($form) . PHP_EOL; + + // Return the output. + return $output; + } +} \ No newline at end of file From a71a5217f4872559baf9775399d596fbe2ff0025 Mon Sep 17 00:00:00 2001 From: Steve Rayner Date: Tue, 5 Nov 2013 14:00:39 +0000 Subject: [PATCH 03/10] added get message to tag and improved form --- src/EdpDiscuss/Form/PostForm.php | 7 +++++- src/EdpDiscuss/Model/Tag/Tag.php | 26 +++++++++++++++++++++++ src/EdpDiscuss/Model/Tag/TagInterface.php | 14 ++++++++++++ src/EdpDiscuss/View/Helper/RenderForm.php | 20 +++++++++++++---- 4 files changed, 62 insertions(+), 5 deletions(-) diff --git a/src/EdpDiscuss/Form/PostForm.php b/src/EdpDiscuss/Form/PostForm.php index 56fb5b0..3653066 100644 --- a/src/EdpDiscuss/Form/PostForm.php +++ b/src/EdpDiscuss/Form/PostForm.php @@ -27,7 +27,9 @@ public function __construct() ), 'attributes' => array( 'type' => 'text', + 'class' => 'form-control', ), + )); $this->add(array( @@ -36,8 +38,11 @@ public function __construct() 'label' => 'Message', ), 'attributes' => array( - 'type' => 'text', + 'type' => 'textarea', + 'class' => 'form-control', + 'rows' => '6', ), + )); // Submit button. diff --git a/src/EdpDiscuss/Model/Tag/Tag.php b/src/EdpDiscuss/Model/Tag/Tag.php index b66c48b..b764f6e 100644 --- a/src/EdpDiscuss/Model/Tag/Tag.php +++ b/src/EdpDiscuss/Model/Tag/Tag.php @@ -15,6 +15,11 @@ class Tag implements TagInterface * @var string */ protected $name; + + /** + * @var string + */ + protected $description; /** * @var string @@ -69,6 +74,27 @@ public function setName($name) return $this; } + /** + * Get description. + * + * @return description + */ + public function getDescription() + { + return $this->description; + } + + /** + * Set description. + * + * @param $description the value to be set + */ + public function setDescription($description) + { + $this->description = $description; + return $this; + } + /** * Get slug. * diff --git a/src/EdpDiscuss/Model/Tag/TagInterface.php b/src/EdpDiscuss/Model/Tag/TagInterface.php index e62fbed..e61b3be 100644 --- a/src/EdpDiscuss/Model/Tag/TagInterface.php +++ b/src/EdpDiscuss/Model/Tag/TagInterface.php @@ -31,6 +31,20 @@ public function getName(); * @param $name the value to be set */ public function setName($name); + + /** + * Get description. + * + * @return description + */ + public function getDescription(); + + /** + * Set description. + * + * @param $description the value to be set + */ + public function setDescription($description); /** * Get slug. diff --git a/src/EdpDiscuss/View/Helper/RenderForm.php b/src/EdpDiscuss/View/Helper/RenderForm.php index 04d10f4..01e35a7 100644 --- a/src/EdpDiscuss/View/Helper/RenderForm.php +++ b/src/EdpDiscuss/View/Helper/RenderForm.php @@ -17,7 +17,13 @@ public function __invoke($form) foreach($elements as $element) { $hidden = ($element->getAttribute('type') == 'hidden'); - + + $offset = ""; + if ($element->getAttribute('type') == 'submit') + { + $offset ="col-sm-offset-2 "; + } + if (!$hidden) { $messages = $element->getMessages(); @@ -32,15 +38,21 @@ public function __invoke($form) $label = $element->getLabel(); if (isset($label) && '' !== $label) { - $element->setLabelAttributes(array('class' => 'control-label')); + $element->setLabelAttributes(array('class' => 'col-sm-2 control-label')); $output .= $this->view->formLabel($element) . PHP_EOL; } // Render the actual element (and any errors) - $output .= '
' . PHP_EOL; + if (!$hidden) + { + $output .= '
' . PHP_EOL; + } $output .= $this->view->formElement($element) . PHP_EOL; $output .= $this->view->formElementErrors($element) . PHP_EOL; - $output .= '
' . PHP_EOL; + if (!$hidden) + { + $output .= '
' . PHP_EOL; + } if (!$hidden) { From c64da172701c00b95cab64bf8649e9ee7038d6a6 Mon Sep 17 00:00:00 2001 From: Steve Rayner Date: Fri, 8 Nov 2013 12:45:52 +0000 Subject: [PATCH 04/10] Added thread count, message count and last message to tag entity. --- src/EdpDiscuss/Model/Tag/Tag.php | 87 ++++++++++++++++++++++++++ src/EdpDiscuss/Model/Tag/TagMapper.php | 22 +++++-- 2 files changed, 105 insertions(+), 4 deletions(-) diff --git a/src/EdpDiscuss/Model/Tag/Tag.php b/src/EdpDiscuss/Model/Tag/Tag.php index b764f6e..08c5211 100644 --- a/src/EdpDiscuss/Model/Tag/Tag.php +++ b/src/EdpDiscuss/Model/Tag/Tag.php @@ -31,6 +31,21 @@ class Tag implements TagInterface */ protected $slugifier; + /** + * @var integer + */ + protected $threadCount; + + /** + * @var integer + */ + protected $messageCount; + + /** + * @var Date + */ + protected $lastPost; + /** * Get tagId. * @@ -116,6 +131,11 @@ public function setSlug($slug) return $this; } + /** + * Get Slugifier. + * + * @return Slugifier + */ public function getSlugifier() { if ($this->slugifier === null) { @@ -124,9 +144,76 @@ public function getSlugifier() return $this->slugifier; } + /** + * Set Slugifier. + * + * @param Slugifier + */ public function setSlugifier($slugifier) { $this->slugifier = $slugifier; return $this; } + + /** + * Set thread count. + * @param integer $threadCount + */ + public function setThreadCount($threadCount) + { + $this->threadCount = $threadCount; + return $this; + } + + /** + * Get thread count. + * + * @return integer + */ + public function getThreadCount() + { + return $this->threadCount; + } + + /** + * Set Message Count. + * + * @param integer $messageCount + */ + public function setMessageCount($messageCount) + { + $this->messageCount = $messageCount; + return $this; + } + + /** + * Get Message Count. + * + * @return integer + */ + public function getMessageCount() + { + return $this->messageCount; + } + + /** + * Set Last Post + * + * @param Date $lastPost + */ + public function setLastPost($lastPost) + { + $this->lastPost = $lastPost; + return $this; + } + + /** + * Get Last Post. + * + * @return Date + */ + public function getLastPost() + { + return $this->lastPost; + } } diff --git a/src/EdpDiscuss/Model/Tag/TagMapper.php b/src/EdpDiscuss/Model/Tag/TagMapper.php index d110e75..5c6ed78 100644 --- a/src/EdpDiscuss/Model/Tag/TagMapper.php +++ b/src/EdpDiscuss/Model/Tag/TagMapper.php @@ -5,6 +5,7 @@ use ZfcBase\Mapper\AbstractDbMapper; use EdpDiscuss\Module as EdpDiscuss; use EdpDiscuss\Service\DbAdapterAwareInterface; +use Zend\Db\Sql\Expression; class TagMapper extends AbstractDbMapper implements TagMapperInterface, DbAdapterAwareInterface { @@ -30,9 +31,22 @@ public function getTagById($tagId) * @return array of TagInterface's */ public function getTags() - { - $select = $this->getSelect(); - $rowset = $this->select($select); - return $rowset; + { + $select = $this->getSelect(); + $select->join(array('tt' => 'discuss_thread_tag'), + 'tt.tag_id = discuss_tag.tag_id', + array(), + 'left') + ->join(array('t' => 'discuss_thread'), + 't.thread_id = tt.thread_id', + array('thread_count' => new Expression('COUNT(DISTINCT t.thread_id)')), + 'left') + ->join(array('m' => 'discuss_message'), + 'm.thread_id = t.thread_id', + array('last_post' => new Expression('MAX(m.post_time)'), + 'message_count' => new Expression('COUNT(m.message_id)')), + 'left') + ->group(array('discuss_tag.name', 'discuss_tag.slug', 'discuss_tag.description')); + return $this->select($select); } } From 114a959b64dc987a19bd6b1b3628e936a10d6565 Mon Sep 17 00:00:00 2001 From: Steve Rayner Date: Fri, 8 Nov 2013 13:45:14 +0000 Subject: [PATCH 05/10] Refactored createMessage method to remove entity validation. --- src/EdpDiscuss/Service/Discuss.php | 23 +++-------------------- 1 file changed, 3 insertions(+), 20 deletions(-) diff --git a/src/EdpDiscuss/Service/Discuss.php b/src/EdpDiscuss/Service/Discuss.php index 74d3597..6dd3766 100644 --- a/src/EdpDiscuss/Service/Discuss.php +++ b/src/EdpDiscuss/Service/Discuss.php @@ -114,29 +114,12 @@ public function updateThread(ThreadInterface $thread) /** * createMessage * - * @param array $data + * @param MessageInterface $message * @return MessageInterface */ - public function createMessage(array $data, $thread) + public function createMessage(MessageInterface $message) { - // Create new message object. - $message = $this->getServiceManager()->get('edpdiscuss_message'); - $message->setThread($thread); - - // Create new form and hydrator objects. - $form = $this->getServiceManager()->get('edpdiscuss_form'); - $formHydrator = $this->getServiceManager()->get('edpdiscuss_post_form_hydrator'); - - // validate data against form - $form->setHydrator($formHydrator); - $form->bind($message); - $form->setData($data); - if (!$form->isValid()) - { - return false; - } - - // Valid, so persist message. + // Set post time and persist message. $message->setPostTime(new \DateTime); $message = $this->messageMapper->persist($message); // $this->events()->trigger(__FUNCTION__, $this, array('message' => $message)); From 7fb97a1b0c1cafb7f939f80a441af9f05f8bc573 Mon Sep 17 00:00:00 2001 From: Steve Rayner Date: Sat, 9 Nov 2013 23:18:10 +0000 Subject: [PATCH 06/10] You can now create new threads and associate with a tag --- Module.php | 4 ++ .../Model/Message/MessageHydrator.php | 8 ---- src/EdpDiscuss/Model/Tag/TagMapper.php | 17 +++++++ .../Model/Thread/ThreadHydrator.php | 44 +++++++++++++++++++ src/EdpDiscuss/Model/Thread/ThreadMapper.php | 42 +++++++++++++++--- src/EdpDiscuss/Service/Discuss.php | 27 +++++++++--- 6 files changed, 121 insertions(+), 21 deletions(-) create mode 100644 src/EdpDiscuss/Model/Thread/ThreadHydrator.php diff --git a/Module.php b/Module.php index b70e853..abbc90b 100644 --- a/Module.php +++ b/Module.php @@ -66,6 +66,10 @@ public function getServiceConfig() $mapper->setHydrator(new \Zend\Stdlib\Hydrator\ClassMethods); return $mapper; }, + 'edpdiscuss_thread' => function ($sm) { + $thread = new \EdpDiscuss\Model\Thread\Thread; + return $thread; + }, 'edpdiscuss_message' => function ($sm) { $message = new \EdpDiscuss\Model\Message\Message; return $message; diff --git a/src/EdpDiscuss/Model/Message/MessageHydrator.php b/src/EdpDiscuss/Model/Message/MessageHydrator.php index 0883498..748c79c 100644 --- a/src/EdpDiscuss/Model/Message/MessageHydrator.php +++ b/src/EdpDiscuss/Model/Message/MessageHydrator.php @@ -30,15 +30,7 @@ public function extract($object) $thread = $object->getThread(); $data['thread_id'] = (int)$thread->getThreadId(); unset($data['thread']); - - $data['post_time'] = $data['post_time']->format('Y-m-d H:i:s'); - - //die(var_dump($data)); - - // Example of how to map fields. - //$data = $this->mapField('id', 'user_id', $data); - return $data; } diff --git a/src/EdpDiscuss/Model/Tag/TagMapper.php b/src/EdpDiscuss/Model/Tag/TagMapper.php index 5c6ed78..3b6bbbe 100644 --- a/src/EdpDiscuss/Model/Tag/TagMapper.php +++ b/src/EdpDiscuss/Model/Tag/TagMapper.php @@ -5,6 +5,7 @@ use ZfcBase\Mapper\AbstractDbMapper; use EdpDiscuss\Module as EdpDiscuss; use EdpDiscuss\Service\DbAdapterAwareInterface; +use Zend\Db\Sql\Sql; use Zend\Db\Sql\Expression; class TagMapper extends AbstractDbMapper implements TagMapperInterface, DbAdapterAwareInterface @@ -49,4 +50,20 @@ public function getTags() ->group(array('discuss_tag.name', 'discuss_tag.slug', 'discuss_tag.description')); return $this->select($select); } + + /** + * Add Thread. + * + * @param integer $tag_id + * @param integer $thread_id + */ + public function addThread($tag_id, $thread_id) + { + $sql = new Sql($this->getDbAdapter()); + $insert = $sql->insert(); + $insert->into('discuss_thread_tag'); + $insert->values(array('tag_id' => $tag_id, 'thread_id' => $thread_id)); + $sql->prepareStatementForSqlObject($insert) + ->execute(); + } } diff --git a/src/EdpDiscuss/Model/Thread/ThreadHydrator.php b/src/EdpDiscuss/Model/Thread/ThreadHydrator.php new file mode 100644 index 0000000..f1ed054 --- /dev/null +++ b/src/EdpDiscuss/Model/Thread/ThreadHydrator.php @@ -0,0 +1,44 @@ +toArray()); if ($thread->getThreadId() > 0) { - $this->getTableGateway()->update((array) $data, array($this->threadIDField => $thread->getThreadId())); + $this->update($thread, null, null, new ThreadHydrator); } else { - $this->getTableGateway()->insert((array) $data); - $threadId = $this->getTableGateway()->getAdapter()->getDriver()->getConnection()->getLastGeneratedId(); - $thread->setThreadId($threadId); + $this->insert($thread, null, new ThreadHydrator); } - + return $thread; } + + /** + * insert - Inserts a new thread into the database, using the specified hydrator. + * + * @param ThreadInterface $entity + * @param String $tableName + * @param HydratorInterface $hydrator + * @return unknown + */ + protected function insert($entity, $tableName = null, HydratorInterface $hydrator = null) + { + $result = parent::insert($entity, $tableName, $hydrator); + $entity->setThreadId($result->getGeneratedValue()); + return $result; + } + + /** + * update - Updates an existing thread in the database. + * @param ThreadInterface $entity + * @param String $where + * @param String $tableName + * @param HydratorInterface $hydrator + */ + protected function update($entity, $where = null, $tableName = null, HydratorInterface $hydrator = null) + { + if (!$where) { + $where = 'thread_id = ' . $entity->getThreadId(); + } + return parent::update($entity, $where, $tableName, $hydrator); + } } diff --git a/src/EdpDiscuss/Service/Discuss.php b/src/EdpDiscuss/Service/Discuss.php index 6dd3766..f4e31b1 100644 --- a/src/EdpDiscuss/Service/Discuss.php +++ b/src/EdpDiscuss/Service/Discuss.php @@ -86,17 +86,16 @@ public function getMessagesByThread(ThreadInterface $thread, $limit = 25, $offse * createThread * * @param ThreadInterface $thread + * @param MessageInterface $message * @return ThreadInterface */ public function createThread(ThreadInterface $thread, MessageInterface $message) { - $message = $this->messageMapper->persist($message); - - $thread->setOriginalMessage($message); + $thread->setSubject($message->getSubject()); $thread = $this->threadMapper->persist($thread); - - $this->events()->trigger(__FUNCTION__, $this, array('thread' => $thread)); - + $message->setPostTime(new \DateTime); + $message = $this->messageMapper->persist($message); + //$this->events()->trigger(__FUNCTION__, $this, array('thread' => $thread)); return $thread; } @@ -245,4 +244,20 @@ public function setTagMapper(TagMapperInterface $tagMapper) $this->tagMapper = $tagMapper; return $this; } + + /** + * Associate tag and thread. + * + * @param TagInterface $tag + * @param ThreadInterface $thread + * @return \EdpDiscuss\Service\Discuss + */ + public function associateTagAndThread(TagInterface $tag, ThreadInterface $thread) + { + $this->getTagMapper()->addThread( + $tag->getTagId(), + $thread->getThreadId() + ); + return $this; + } } From 53a99323012d9f00948e305836000868f9285209 Mon Sep 17 00:00:00 2001 From: Steve Rayner Date: Sun, 10 Nov 2013 23:16:29 +0000 Subject: [PATCH 07/10] Can now create new threads. Also added new visit model. --- data/schema.sql | 9 ++ src/EdpDiscuss/Model/Thread/Thread.php | 52 ++++++++++++ .../Model/Thread/ThreadHydrator.php | 2 + src/EdpDiscuss/Model/Thread/ThreadMapper.php | 30 ++++--- src/EdpDiscuss/Model/Visit/Visit.php | 84 +++++++++++++++++++ src/EdpDiscuss/Model/Visit/VisitHydrator.php | 44 ++++++++++ src/EdpDiscuss/Model/Visit/VisitInterface.php | 42 ++++++++++ src/EdpDiscuss/Model/Visit/VisitMapper.php | 27 ++++++ src/EdpDiscuss/Service/Discuss.php | 11 +++ 9 files changed, 288 insertions(+), 13 deletions(-) create mode 100644 src/EdpDiscuss/Model/Visit/Visit.php create mode 100644 src/EdpDiscuss/Model/Visit/VisitHydrator.php create mode 100644 src/EdpDiscuss/Model/Visit/VisitInterface.php create mode 100644 src/EdpDiscuss/Model/Visit/VisitMapper.php diff --git a/data/schema.sql b/data/schema.sql index 8739383..4b6a040 100644 --- a/data/schema.sql +++ b/data/schema.sql @@ -35,3 +35,12 @@ CREATE TABLE discuss_thread_tag FOREIGN KEY (thread_id) REFERENCES discuss_thread (thread_id), FOREIGN KEY (tag_id) REFERENCES discuss_tag (tag_id) ) ENGINE=InnoDB; + +CREATE TABLE discuss_visit +( + ip_address VARCHAR(45) NOT NULL, + thread_id INT UNSIGNED NOT NULL, + visit_time DATETIME NOT NULL, + PRIMARY KEY(ip_address, thread_id), + FOREIGN KEY (thread_id) REFERENCES discuss_thread(thread_id) +) ENGINE=InnoDB; \ No newline at end of file diff --git a/src/EdpDiscuss/Model/Thread/Thread.php b/src/EdpDiscuss/Model/Thread/Thread.php index 5559a78..7f2a972 100644 --- a/src/EdpDiscuss/Model/Thread/Thread.php +++ b/src/EdpDiscuss/Model/Thread/Thread.php @@ -38,6 +38,16 @@ class Thread implements ThreadInterface */ protected $slugifier; + /** + * @var integer + */ + protected $messageCount; + + /** + * @var Date + */ + protected $lastPost; + /** * Get threadId. * @@ -157,4 +167,46 @@ public function setSlugifier($slugifier) $this->slugifier = $slugifier; return $this; } + + /** + * Set Message Count. + * + * @param integer $messageCount + */ + public function setMessageCount($messageCount) + { + $this->messageCount = $messageCount; + return $this; + } + + /** + * Get Message Count. + * + * @return integer + */ + public function getMessageCount() + { + return $this->messageCount; + } + + /** + * Set Last Post + * + * @param Date $lastPost + */ + public function setLastPost($lastPost) + { + $this->lastPost = $lastPost; + return $this; + } + + /** + * Get Last Post. + * + * @return Date + */ + public function getLastPost() + { + return $this->lastPost; + } } diff --git a/src/EdpDiscuss/Model/Thread/ThreadHydrator.php b/src/EdpDiscuss/Model/Thread/ThreadHydrator.php index f1ed054..8faf31f 100644 --- a/src/EdpDiscuss/Model/Thread/ThreadHydrator.php +++ b/src/EdpDiscuss/Model/Thread/ThreadHydrator.php @@ -23,6 +23,8 @@ public function extract($object) unset($data['original_message']); unset($data['latest_message']); unset($data['slugifier']); + unset($data['message_count']); + unset($data['last_post']); return $data; } diff --git a/src/EdpDiscuss/Model/Thread/ThreadMapper.php b/src/EdpDiscuss/Model/Thread/ThreadMapper.php index 7adabb5..0fb3186 100644 --- a/src/EdpDiscuss/Model/Thread/ThreadMapper.php +++ b/src/EdpDiscuss/Model/Thread/ThreadMapper.php @@ -5,6 +5,7 @@ use ZfcBase\Mapper\AbstractDbMapper; use EdpDiscuss\Module as EdpDiscuss; use Zend\Db\Sql\Select; +use Zend\Db\Sql\Expression; use EdpDiscuss\Service\DbAdapterAwareInterface; use Zend\Stdlib\Hydrator\HydratorInterface; @@ -35,18 +36,20 @@ public function getThreadById($threadId) */ public function getLatestThreads($limit = 25, $offset = 0, $tagId = false) { - if ($tagId) { - $select = new Select(); - // @TODO: Join the original and latest messages - $select->from('discuss_thread') - ->join('discuss_thread_tag', 'discuss_thread_tag.thread_id = discuss_thread.thread_id') - ->where(array('tag_id = ?' => $tagId)); - $rowset = $this->select($select); - } else { - $rowset = $this->select(); - } - - return $rowset; + $select = $this->getSelect(); + $select->join(array('tt' => 'discuss_thread_tag'), + 'tt.thread_id = discuss_thread.thread_id', + array()) + ->join(array('m' => 'discuss_message'), + 'm.thread_id = discuss_thread.thread_id', + array( + 'message_count' => new Expression('COUNT(DISTINCT m.message_id)'), + 'last_post' => new Expression('MAX(m.post_time)') + ), + 'left') + ->where(array('tag_id = ?' => $tagId)) + ->group(array('discuss_thread.subject', 'discuss_thread.slug')); + return $this->select($select); } /** @@ -75,7 +78,8 @@ public function persist(ThreadInterface $thread) * @return unknown */ protected function insert($entity, $tableName = null, HydratorInterface $hydrator = null) - { + { + //die(var_dump($entity)); $result = parent::insert($entity, $tableName, $hydrator); $entity->setThreadId($result->getGeneratedValue()); return $result; diff --git a/src/EdpDiscuss/Model/Visit/Visit.php b/src/EdpDiscuss/Model/Visit/Visit.php new file mode 100644 index 0000000..ea459a2 --- /dev/null +++ b/src/EdpDiscuss/Model/Visit/Visit.php @@ -0,0 +1,84 @@ +ipAddress = $ipAddress; + return $this; + } + + /** + * getIpAddress - Returns the IP address. + */ + public function getIpAddress() + { + return $this->ipAddress; + } + + /** + * setVisitTime - Sets the visit time. + * + * @param unknown_type $visitTime + * @return \EdpDiscuss\Model\Visit\Visit + */ + public function setVisitTime($visitTime) + { + if ($visitTime instanceof DateTime) { + $this->visitTime = $visitTime; + } else { + $this->visitTime = new DateTime($visitTime); + } + return $this; + } + + /** + * getVisitTime - returns the visit time. + */ + public function getVisitTime() + { + return $this->visitTime; + } + + /** + * setThread - Sets the thread. + * + * @return \EdpDiscuss\Model\Visit\Visit + */ + public function setThread() + { + $this->thread = $thread; + return $this; + } + + /** + * getThread - returns the thread. + */ + public function getThread() + { + return $this->thread; + } +} diff --git a/src/EdpDiscuss/Model/Visit/VisitHydrator.php b/src/EdpDiscuss/Model/Visit/VisitHydrator.php new file mode 100644 index 0000000..8c6de7c --- /dev/null +++ b/src/EdpDiscuss/Model/Visit/VisitHydrator.php @@ -0,0 +1,44 @@ +getThread(); + $data['thread_id'] = (int)$thread->getThreadId(); + unset($data['thread']); + $data['visit_time'] = $data['visit_time']->format('Y-m-d H:i:s'); + return $date; + } + + /** + * hydrate + * + * @param array $data + * @param unknown_type $object + * @throws Exception\InvalidArgumentException + */ + public function hydrate(array $data, $object) + { + if (!$object instanceof VisitInterface) { + throw new Exception\InvalidArgumentException('$object must be an instance of EdpDiscuss\Model\Visit\VisitInterface'); + } + + return parent::hydrate($data, $object); + } +} \ No newline at end of file diff --git a/src/EdpDiscuss/Model/Visit/VisitInterface.php b/src/EdpDiscuss/Model/Visit/VisitInterface.php new file mode 100644 index 0000000..a3dadb4 --- /dev/null +++ b/src/EdpDiscuss/Model/Visit/VisitInterface.php @@ -0,0 +1,42 @@ +getSelect() + ->where(array( + ipAddress => $visit->getIpAddress(), + threadId => $visit->getThread->getThreadId() + )); + $result = $this->select($select)->current(); + if (!$result) { + parent::insert($visit, null, new VisitHydrator); + return true; + } else { + return false; + } + } +} \ No newline at end of file diff --git a/src/EdpDiscuss/Service/Discuss.php b/src/EdpDiscuss/Service/Discuss.php index f4e31b1..0cf3508 100644 --- a/src/EdpDiscuss/Service/Discuss.php +++ b/src/EdpDiscuss/Service/Discuss.php @@ -260,4 +260,15 @@ public function associateTagAndThread(TagInterface $tag, ThreadInterface $thread ); return $this; } + + /** + * storeVisitIfUnique - records the visit if it is unuiqe. + * @param ThreadInterface $thread + * @return \EdpDiscuss\Service\Discuss + */ + public function storeVisitIfUnique(ThreadInterface $thread) + { + $this->getThreadMapper()->storeVisitIfUnique($thread); + return $this; + } } From d989f4df4470f1abc8efb30c49437b4279c09b81 Mon Sep 17 00:00:00 2001 From: Steve Rayner Date: Mon, 11 Nov 2013 13:33:38 +0000 Subject: [PATCH 08/10] now keeps a basic track of visits --- Module.php | 16 ++++++++++- config/module.config.php | 1 + src/EdpDiscuss/Model/Thread/Thread.php | 27 ++++++++++++++++++ .../Model/Thread/ThreadHydrator.php | 1 + src/EdpDiscuss/Model/Thread/ThreadMapper.php | 7 +++++ src/EdpDiscuss/Model/Visit/Visit.php | 9 ++++-- src/EdpDiscuss/Model/Visit/VisitHydrator.php | 2 +- src/EdpDiscuss/Model/Visit/VisitInterface.php | 4 ++- src/EdpDiscuss/Model/Visit/VisitMapper.php | 4 +-- .../Model/Visit/VisitMapperInterface.php | 7 +++++ src/EdpDiscuss/Service/Discuss.php | 28 +++++++++++++++++-- 11 files changed, 96 insertions(+), 10 deletions(-) create mode 100644 src/EdpDiscuss/Model/Visit/VisitMapperInterface.php diff --git a/Module.php b/Module.php index abbc90b..e372586 100644 --- a/Module.php +++ b/Module.php @@ -38,7 +38,8 @@ public function getServiceConfig() $service = new \EdpDiscuss\Service\Discuss; $service->setThreadMapper($sm->get('edpdiscuss_thread_mapper')) ->setMessageMapper($sm->get('edpdiscuss_message_mapper')) - ->setTagMapper($sm->get('edpdiscuss_tag_mapper')); + ->setTagMapper($sm->get('edpdiscuss_tag_mapper')) + ->setVisitMapper($sm->get('edpdiscuss_visit_mapper')); return $service; }, 'edpdiscuss_thread_mapper' => function($sm) { @@ -66,6 +67,13 @@ public function getServiceConfig() $mapper->setHydrator(new \Zend\Stdlib\Hydrator\ClassMethods); return $mapper; }, + 'edpdiscuss_visit_mapper' => function($sm) { + $mapper = new \EdpDiscuss\Model\Visit\VisitMapper; + $visitModelClass = Module::getOption('visit_model_class'); + $mapper->setEntityPrototype(new $visitModelClass); + $mapper->setHydrator(new \Zend\StdLib\Hydrator\ClassMethods); + return $mapper; + }, 'edpdiscuss_thread' => function ($sm) { $thread = new \EdpDiscuss\Model\Thread\Thread; return $thread; @@ -78,6 +86,12 @@ public function getServiceConfig() $form = new \EdpDiscuss\Form\PostForm; return $form; }, + 'edpdiscuss_visit' => function ($sm) { + $visit = new \EdpDiscuss\Model\Visit\Visit; + $visit->setIpAddress($_SERVER['REMOTE_ADDR']) + ->setVisitTime(new \DateTime); + return $visit; + } ), 'initializers' => array( function($instance, $sm){ diff --git a/config/module.config.php b/config/module.config.php index bdc6185..5784caf 100644 --- a/config/module.config.php +++ b/config/module.config.php @@ -4,6 +4,7 @@ 'thread_model_class' => 'EdpDiscuss\Model\Thread\Thread', 'message_model_class' => 'EdpDiscuss\Model\Message\Message', 'tag_model_class' => 'EdpDiscuss\Model\Tag\Tag', + 'visit_model_class' => 'EdpDiscuss\Model\Visit\Visit' ), 'service_manager' => array( 'aliases' => array( diff --git a/src/EdpDiscuss/Model/Thread/Thread.php b/src/EdpDiscuss/Model/Thread/Thread.php index 7f2a972..7f4b8f6 100644 --- a/src/EdpDiscuss/Model/Thread/Thread.php +++ b/src/EdpDiscuss/Model/Thread/Thread.php @@ -43,6 +43,11 @@ class Thread implements ThreadInterface */ protected $messageCount; + /** + * @var integer + */ + protected $visitCount; + /** * @var Date */ @@ -189,6 +194,28 @@ public function getMessageCount() return $this->messageCount; } + /** + * Set View Count + * + * Enter description here ... + * @param unknown_type $viewCount + */ + public function setVisitCount($viewCount) + { + $this->viewCount = $viewCount; + return $this; + } + + /** + * Get View Count + * + * @return integer + */ + public function getVisitCount() + { + return $this->viewCount; + } + /** * Set Last Post * diff --git a/src/EdpDiscuss/Model/Thread/ThreadHydrator.php b/src/EdpDiscuss/Model/Thread/ThreadHydrator.php index 8faf31f..2c895c3 100644 --- a/src/EdpDiscuss/Model/Thread/ThreadHydrator.php +++ b/src/EdpDiscuss/Model/Thread/ThreadHydrator.php @@ -24,6 +24,7 @@ public function extract($object) unset($data['latest_message']); unset($data['slugifier']); unset($data['message_count']); + unset($data['visit_count']); unset($data['last_post']); return $data; } diff --git a/src/EdpDiscuss/Model/Thread/ThreadMapper.php b/src/EdpDiscuss/Model/Thread/ThreadMapper.php index 0fb3186..a5b7012 100644 --- a/src/EdpDiscuss/Model/Thread/ThreadMapper.php +++ b/src/EdpDiscuss/Model/Thread/ThreadMapper.php @@ -47,8 +47,15 @@ public function getLatestThreads($limit = 25, $offset = 0, $tagId = false) 'last_post' => new Expression('MAX(m.post_time)') ), 'left') + ->join(array('v' => 'discuss_visit'), + 'v.thread_id = discuss_thread.thread_id', + array( + 'visit_count' => new Expression('COUNT(DISTINCT v.ip_address)') + ), + 'left') ->where(array('tag_id = ?' => $tagId)) ->group(array('discuss_thread.subject', 'discuss_thread.slug')); + //die($select->getSqlString()); return $this->select($select); } diff --git a/src/EdpDiscuss/Model/Visit/Visit.php b/src/EdpDiscuss/Model/Visit/Visit.php index ea459a2..db55755 100644 --- a/src/EdpDiscuss/Model/Visit/Visit.php +++ b/src/EdpDiscuss/Model/Visit/Visit.php @@ -2,6 +2,8 @@ namespace EdpDiscuss\Model\Visit; +use EdpDiscuss\Model\Thread\ThreadInterface; + class Visit implements VisitInterface { /** @@ -47,10 +49,10 @@ public function getIpAddress() */ public function setVisitTime($visitTime) { - if ($visitTime instanceof DateTime) { + if ($visitTime instanceof \DateTime) { $this->visitTime = $visitTime; } else { - $this->visitTime = new DateTime($visitTime); + $this->visitTime = new \DateTime($visitTime); } return $this; } @@ -66,9 +68,10 @@ public function getVisitTime() /** * setThread - Sets the thread. * + * @param ThreadInterface $thread * @return \EdpDiscuss\Model\Visit\Visit */ - public function setThread() + public function setThread(ThreadInterface $thread) { $this->thread = $thread; return $this; diff --git a/src/EdpDiscuss/Model/Visit/VisitHydrator.php b/src/EdpDiscuss/Model/Visit/VisitHydrator.php index 8c6de7c..55830f3 100644 --- a/src/EdpDiscuss/Model/Visit/VisitHydrator.php +++ b/src/EdpDiscuss/Model/Visit/VisitHydrator.php @@ -23,7 +23,7 @@ public function extract($object) $data['thread_id'] = (int)$thread->getThreadId(); unset($data['thread']); $data['visit_time'] = $data['visit_time']->format('Y-m-d H:i:s'); - return $date; + return $data; } /** diff --git a/src/EdpDiscuss/Model/Visit/VisitInterface.php b/src/EdpDiscuss/Model/Visit/VisitInterface.php index a3dadb4..5ad87a5 100644 --- a/src/EdpDiscuss/Model/Visit/VisitInterface.php +++ b/src/EdpDiscuss/Model/Visit/VisitInterface.php @@ -2,6 +2,8 @@ namespace EdpDiscuss\Model\Visit; +use EdpDiscuss\Model\Thread\ThreadInterface; + interface VisitInterface { /** @@ -33,7 +35,7 @@ public function getVisitTime(); * * @param unknown_type $thread */ - public function setThread($thread); + public function setThread(ThreadInterface $thread); /** * getThread diff --git a/src/EdpDiscuss/Model/Visit/VisitMapper.php b/src/EdpDiscuss/Model/Visit/VisitMapper.php index 3b28da4..51d6d4e 100644 --- a/src/EdpDiscuss/Model/Visit/VisitMapper.php +++ b/src/EdpDiscuss/Model/Visit/VisitMapper.php @@ -13,8 +13,8 @@ public function storeVisitIfUnique($visit) { $select = $this->getSelect() ->where(array( - ipAddress => $visit->getIpAddress(), - threadId => $visit->getThread->getThreadId() + 'ip_address' => $visit->getIpAddress(), + 'thread_id' => $visit->getThread()->getThreadId() )); $result = $this->select($select)->current(); if (!$result) { diff --git a/src/EdpDiscuss/Model/Visit/VisitMapperInterface.php b/src/EdpDiscuss/Model/Visit/VisitMapperInterface.php new file mode 100644 index 0000000..d0e91ed --- /dev/null +++ b/src/EdpDiscuss/Model/Visit/VisitMapperInterface.php @@ -0,0 +1,7 @@ +visitMapper = $visitMapper; + return $this; + } + + /** + * Get Vist Mapper. + * + * Enter description here ... + */ + public function getVisitMapper() + { + return $this->visitMapper; + } + /** * Associate tag and thread. * @@ -266,9 +290,9 @@ public function associateTagAndThread(TagInterface $tag, ThreadInterface $thread * @param ThreadInterface $thread * @return \EdpDiscuss\Service\Discuss */ - public function storeVisitIfUnique(ThreadInterface $thread) + public function storeVisitIfUnique(VisitInterface $visit) { - $this->getThreadMapper()->storeVisitIfUnique($thread); + $this->getVisitMapper()->storeVisitIfUnique($visit); return $this; } } From 329fc3ff7ff4adf70335d3b5cd747e00eb4d23b4 Mon Sep 17 00:00:00 2001 From: Steve Rayner Date: Mon, 11 Nov 2013 13:53:37 +0000 Subject: [PATCH 09/10] Updated readme.md --- README.md | 35 ++++++++++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 1bc8e42..deb701c 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,8 @@ Requirements ------------ * [Zend Framework 2](https://github.com/zendframework/zf2) (latest master) -* [ZfcBase](https://github.com/ZF-Commons/ZfcBase) (latest master). +* [ZfcBase](https://github.com/ZF-Commons/ZfcBase) (latest master) +* [BaconStringUtils] (https://github.com/Bacon/BaconStringUtils) Installation ------------ @@ -17,16 +18,44 @@ Installation 1. Install the [ZfcBase](https://github.com/ZF-Commons/ZfcBase) ZF2 module by cloning it into `./vendor/`. -2. Clone this project into your `./vendor/` directory. +2. Install the [BaconStringUtils] (https://github.com/Bacon/BaconStringUtils) ZF2 module + by cloning it into `./vendor/`. +3. Clone this project into your `./vendor/` directory. Post Installation ----------------- -Import the SQL schema located in `./vendor/EdpDiscuss/data/schema.sql`. +1. Enabling the modules in your `application.config.php` file. + + ```php + array( + // ... + 'ZfcBase', + 'BaconStringUtils', + 'EdpDiscuss', + ), + // ... + ); + ``` +2. Import the SQL schema located in `./vendor/EdpDiscuss/data/schema.sql`. Introduction ------------ EdpDiscuss is a module for Zend Framework 2. + +Options +------- + +The EdpDiscuss module has various options to allow you to quickly customize the basic functionality. + +The following options are available: + +- **thread_model_class** - Name of Thread entity class to use. +- **message_model_class** - Name of Message entity class to use. +- **tag_model_class** - Name of Tag entity class to use. +- **visit_model_class** - Name of Visit Entity class to use. \ No newline at end of file From 10a4e7c067fa2cff3ac4fbb5581965bf7aa58c3a Mon Sep 17 00:00:00 2001 From: Steve Rayner Date: Tue, 12 Nov 2013 21:09:32 +0000 Subject: [PATCH 10/10] lastPost property on Tag and Thread is now a DateTime value. --- src/EdpDiscuss/Model/Tag/Tag.php | 9 +++++++-- src/EdpDiscuss/Model/Thread/Thread.php | 15 ++++++++++----- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/src/EdpDiscuss/Model/Tag/Tag.php b/src/EdpDiscuss/Model/Tag/Tag.php index 08c5211..7a72366 100644 --- a/src/EdpDiscuss/Model/Tag/Tag.php +++ b/src/EdpDiscuss/Model/Tag/Tag.php @@ -3,6 +3,7 @@ namespace EdpDiscuss\Model\Tag; use BaconStringUtils\Slugifier; +use DateTime; class Tag implements TagInterface { @@ -203,8 +204,12 @@ public function getMessageCount() */ public function setLastPost($lastPost) { - $this->lastPost = $lastPost; - return $this; + if ($lastPost instanceof DateTime) { + $this->lastPost = $lastPost; + } else { + $this->lastPost = new DateTime($lastPost); + } + return $this; } /** diff --git a/src/EdpDiscuss/Model/Thread/Thread.php b/src/EdpDiscuss/Model/Thread/Thread.php index 7f4b8f6..7578bf6 100644 --- a/src/EdpDiscuss/Model/Thread/Thread.php +++ b/src/EdpDiscuss/Model/Thread/Thread.php @@ -2,9 +2,10 @@ namespace EdpDiscuss\Model\Thread; -use ZfcBase\Model\ModelAbstract, - BaconStringUtils\Slugifier, - EdpDiscuss\Model\Message\MessageInterface; +use ZfcBase\Model\ModelAbstract; +use BaconStringUtils\Slugifier; +use EdpDiscuss\Model\Message\MessageInterface; +use DateTime; class Thread implements ThreadInterface { @@ -219,11 +220,15 @@ public function getVisitCount() /** * Set Last Post * - * @param Date $lastPost + * @param DateTime $lastPost */ public function setLastPost($lastPost) { - $this->lastPost = $lastPost; + if ($lastPost instanceof DateTime) { + $this->lastPost = $lastPost; + } else { + $this->lastPost = new DateTime($lastPost); + } return $this; }