From 9a1f84243753c1e62bd37c0f572a8b3caf64351d Mon Sep 17 00:00:00 2001 From: Ryan Cramer Date: Fri, 3 Apr 2020 09:18:39 -0400 Subject: [PATCH] Additional upgrades to FieldtypeComments and its related classes --- wire/core/WireFileTools.php | 2 +- .../Fieldtype/FieldtypeComments/Comment.php | 18 ++++++- .../FieldtypeComments/CommentArray.php | 30 ------------ .../FieldtypeComments/CommentList.php | 49 +++++++++++++++---- .../FieldtypeComments/CommentListCustom.php | 23 ++++++--- .../FieldtypeComments.module | 30 ++++++++---- 6 files changed, 94 insertions(+), 58 deletions(-) diff --git a/wire/core/WireFileTools.php b/wire/core/WireFileTools.php index 9fdbf809..18c5e9f7 100644 --- a/wire/core/WireFileTools.php +++ b/wire/core/WireFileTools.php @@ -937,7 +937,7 @@ class WireFileTools extends Wire { } // render file and return output - $t = new TemplateFile(); + $t = $this->wire(new TemplateFile()); /** @var TemplateFile $t */ $t->setThrowExceptions($options['throwExceptions']); $t->setFilename($filename); diff --git a/wire/modules/Fieldtype/FieldtypeComments/Comment.php b/wire/modules/Fieldtype/FieldtypeComments/Comment.php index fb230b69..e5c4fae3 100644 --- a/wire/modules/Fieldtype/FieldtypeComments/Comment.php +++ b/wire/modules/Fieldtype/FieldtypeComments/Comment.php @@ -33,6 +33,7 @@ * @property-read CommentArray $children Immediate child comments (since 3.0.149) * @property-read int $depth Current comment depth (since 3.0.149) * @property-read bool $loaded True when comment is fully loaded from DB (since 3.0.149) + * @property-read int $numChildren Number of children with no exclusions. See and use numChildren() method for more options. (since 3.0.154) * */ @@ -152,6 +153,12 @@ class Comment extends WireData { */ protected $textFormatted = null; + /** + * @var int|null + * + */ + protected $numChildren = null; + /** * Construct a Comment and set defaults * @@ -228,6 +235,9 @@ class Comment extends WireData { } else if($key === 'loaded') { return $this->loaded; + + } else if($key === 'numChildren') { + return $this->numChildren(); } return parent::get($key); @@ -301,6 +311,9 @@ class Comment extends WireData { } else if($key === 'textFormatted') { $this->textFormatted = $value; return $this; + } else if($key === 'numChildren') { + $this->numChildren = (int) $value; + return $this; } // save the state so that modules can identify when a comment that was identified as spam @@ -541,13 +554,16 @@ class Comment extends WireData { * */ public function numChildren(array $options = array()) { + if(empty($options) && $this->numChildren !== null) return $this->numChildren; $options['parent'] = $this->id; $field = $this->getField(); if(!$field) return null; /** @var FieldtypeComments $fieldtype */ $fieldtype = $field->type; if(!$fieldtype) return 0; - return $fieldtype->getNumComments($this->getPage(), $field, $options); + $numChildren = $fieldtype->getNumComments($this->getPage(), $field, $options); + if(empty($options)) $this->numChildren = $numChildren; + return $numChildren; } /** diff --git a/wire/modules/Fieldtype/FieldtypeComments/CommentArray.php b/wire/modules/Fieldtype/FieldtypeComments/CommentArray.php index fe4b9b03..45d3ee12 100644 --- a/wire/modules/Fieldtype/FieldtypeComments/CommentArray.php +++ b/wire/modules/Fieldtype/FieldtypeComments/CommentArray.php @@ -30,36 +30,6 @@ class CommentArray extends PaginatedArray implements WirePaginatable { */ protected $field = null; - /** - * Total number of comments, including those here and others that aren't, but may be here in pagination. - * - * @var int - * - */ - protected $numTotal = 0; - - /** - * If this CommentArray is a partial representation of a larger set, this will contain the max number - * of comments allowed to be present/loaded in the CommentArray at once. - * - * May vary from count() when on the last page of a result set. - * As a result, paging routines should refer to their own itemsPerPage rather than count(). - * Applicable for paginated result sets. This number is not enforced for adding items to this CommentArray. - * - * @var int - * - */ - protected $numLimit = 0; - - /** - * If this CommentArray is a partial representation of a larger set, this will contain the starting result - * number if previous results preceded it. - * - * @var int - * - */ - protected $numStart = 0; - /** * Per the WireArray interface, is the item a Comment * diff --git a/wire/modules/Fieldtype/FieldtypeComments/CommentList.php b/wire/modules/Fieldtype/FieldtypeComments/CommentList.php index 4d576347..65fd42af 100644 --- a/wire/modules/Fieldtype/FieldtypeComments/CommentList.php +++ b/wire/modules/Fieldtype/FieldtypeComments/CommentList.php @@ -40,6 +40,14 @@ class CommentList extends Wire implements CommentListInterface { */ protected $comments = null; + /** + * Current comment being rendered (or last one rendered) + * + * @var Comment|null + * + */ + protected $comment = null; + /** * @var Page * @@ -169,7 +177,16 @@ class CommentList extends Wire implements CommentListInterface { $commentID = (int) $commentID; $admin = $this->options['admin']; $replies = array(); - foreach($this->comments as $c) { + $comments = $this->comments; + if($commentID && $comments->data('selectors') && $this->comment && $this->comment->id == $commentID) { + // comment originated from a find() + /** @var FieldtypeComments $fieldtype */ + $fieldtype = $this->field->type; + $comments = $fieldtype->find("parent_id=$commentID"); + } else { + $comments = $this->comments; + } + foreach($comments as $c) { if($c->parent_id != $commentID) continue; if(!$admin && $c->status < Comment::statusApproved) continue; $replies[] = $c; @@ -244,7 +261,8 @@ class CommentList extends Wire implements CommentListInterface { if(!count($comments)) return $out; foreach($comments as $comment) { - $out .= $this->renderItem($comment, $depth); + $this->comment = $comment; + $out .= $this->renderItem($comment, array('depth' => $depth)); } if(!$out) return ''; @@ -326,16 +344,17 @@ class CommentList extends Wire implements CommentListInterface { * using your own code in your templates. * * @param Comment $comment - * @param int $depth Default=0 + * @param array $options * @return string * @see CommentArray::render() * */ - public function renderItem(Comment $comment, $depth = 0) { + public function renderItem(Comment $comment, $options = array()) { + if(is_int($options)) $options = array('depth' => $options); if($this->wire('hooks')->isHooked("CommentList::renderItem()")) { - return $this->__call('renderItem', array($comment, $depth)); + return $this->__call('renderItem', array($comment, $options)); } else { - return $this->___renderItem($comment, $depth); + return $this->___renderItem($comment, $options); } } @@ -345,13 +364,19 @@ class CommentList extends Wire implements CommentListInterface { * Hookable since 3.0.138 * * @param Comment $comment - * @param int $depth Default=0 + * @param array|int $options Options array * @return string * @see CommentArray::render() * */ - protected function ___renderItem(Comment $comment, $depth = 0) { + protected function ___renderItem(Comment $comment, $options = array()) { + + $defaults = array( + 'depth' => is_int($options) ? $options : 0, + 'placeholders' => array(), + ); + $options = is_array($options) ? array_merge($defaults, $options) : $defaults; $text = $comment->getFormatted('text'); $cite = $comment->getFormatted('cite'); @@ -370,6 +395,9 @@ class CommentList extends Wire implements CommentListInterface { 'created' => $created, 'gravatar' => $gravatar ); + if(count($options['placeholders'])) { + $placeholders = array_merge($placeholders, $options['placeholders']); + } if(empty($this->options['commentHeader'])) { $header = "$cite $created "; @@ -381,7 +409,8 @@ class CommentList extends Wire implements CommentListInterface { $footer = $this->populatePlaceholders($comment, $this->options['commentFooter'], $placeholders); $liClass = ''; - $replies = $this->options['depth'] > 0 ? $this->renderList($comment->id, $depth+1) : ''; + $replies = $this->options['depth'] > 0 ? $this->renderList($comment->id, $options['depth']+1) : ''; + if($replies) $liClass .= ' CommentHasReplies'; if($comment->status == Comment::statusPending) { $liClass .= ' CommentStatusPending'; @@ -406,7 +435,7 @@ class CommentList extends Wire implements CommentListInterface { $permalink = ''; } - if($this->options['depth'] > 0 && $depth < $this->options['depth']) { + if($this->options['depth'] > 0 && $options['depth'] < $this->options['depth']) { $numReplies = isset($this->numReplies[$comment->id]) ? $this->numReplies[$comment->id] : 0; if($replies && $numReplies && $this->options['useRepliesLink']) { $repliesLabel = ($numReplies == 1 ? $this->options['repliesLabelOne'] : $this->options['repliesLabelMulti']); diff --git a/wire/modules/Fieldtype/FieldtypeComments/CommentListCustom.php b/wire/modules/Fieldtype/FieldtypeComments/CommentListCustom.php index 9edb2835..43c4a7d3 100644 --- a/wire/modules/Fieldtype/FieldtypeComments/CommentListCustom.php +++ b/wire/modules/Fieldtype/FieldtypeComments/CommentListCustom.php @@ -131,7 +131,8 @@ class CommentListCustom extends CommentList { $out = $parent_id ? '' : $this->renderCheckActions(); $comments = $this->options['depth'] > 0 ? $this->getReplies($parent_id) : $this->comments; foreach($comments as $comment) { - $out .= $this->renderItem($comment, $depth); + $this->comment = $comment; + $out .= $this->renderItem($comment, array('depth' => $depth)); } if($out) { $class = implode(' ', $this->getCommentListClasses($parent_id)); @@ -152,13 +153,19 @@ class CommentListCustom extends CommentList { * Render the comment * * @param Comment $comment - * @param int $depth Default=0 + * @param array|int $options Options array * @return string * @see CommentArray::render() * */ - protected function ___renderItem(Comment $comment, $depth = 0) { + protected function ___renderItem(Comment $comment, $options = array()) { + + $defaults = array( + 'depth' => is_int($options) ? $options : 0, + 'placeholders' => array(), + ); + $options = is_array($options) ? array_merge($defaults, $options) : $defaults; $text = $comment->getFormatted('text'); $cite = $comment->getFormatted('cite'); $created = wireDate($this->options['dateFormat'], $comment->created); @@ -180,7 +187,7 @@ class CommentListCustom extends CommentList { $cite = str_replace(array('{href}', '{cite}'), array($website, $cite), $this->markup['website']); } - $sublist = $this->options['depth'] > 0 ? $this->renderList($comment->id, $depth+1) : ''; + $sublist = $this->options['depth'] > 0 ? $this->renderList($comment->id, $options['depth']+1) : ''; if($this->options['usePermalink']) { $permalink = $comment->getPage()->httpUrl; @@ -191,7 +198,7 @@ class CommentListCustom extends CommentList { $permalink = str_replace(array('{href}', '{label}'), array($permalink, $label), $this->markup['permalink']); } - if($this->options['depth'] > 0 && $depth < $this->options['depth']) { + if($this->options['depth'] > 0 && $options['depth'] < $this->options['depth']) { $label = $this->_('Reply'); $reply = str_replace(array('{id}', '{label}'), array($comment->id, $label), $this->markup['reply']); } @@ -223,7 +230,11 @@ class CommentListCustom extends CommentList { 'sublist' => $sublist, ); - $itemMarkup = $depth ? $this->markup['subitem'] : $this->markup['item']; + if(count($options['placeholders'])) { + $placeholders = array_merge($placeholders, $options['placeholders']); + } + + $itemMarkup = $options['depth'] ? $this->markup['subitem'] : $this->markup['item']; if(empty($itemMarkup)) $itemMarkup = $this->markup['item']; $out = $this->populatePlaceholders($comment, $itemMarkup, $placeholders); diff --git a/wire/modules/Fieldtype/FieldtypeComments/FieldtypeComments.module b/wire/modules/Fieldtype/FieldtypeComments/FieldtypeComments.module index a7332bbc..24454f25 100644 --- a/wire/modules/Fieldtype/FieldtypeComments/FieldtypeComments.module +++ b/wire/modules/Fieldtype/FieldtypeComments/FieldtypeComments.module @@ -1278,10 +1278,12 @@ class FieldtypeComments extends FieldtypeMulti { $selectQuery->orderby(implode(',', $sorts)); $selectQuery->limit("$start,$limit"); + /** @var CommentArray $comments */ $comments = $this->wire(new CommentArray()); $comments->setField($field); $comments->setStart($start); $comments->setLimit($limit); + $comments->data('selectors', $selectors); // only present on CommentArray from find() $sql = $selectQuery->getQuery(); $query = $database->prepare($sql); @@ -1353,8 +1355,8 @@ class FieldtypeComments extends FieldtypeMulti { /** * Given a comment code or subcode, return the associated comment ID or 0 if it doesn't exist * - * @param $page - * @param $field + * @param Page|int $page + * @param Field|string $field * @param $code * @return Comment|null * @@ -1380,26 +1382,34 @@ class FieldtypeComments extends FieldtypeMulti { /** * Get a comment by ID or NULL if not found * - * @param $page - * @param $field - * @param $id + * @param Page|int|null $page Provide Page object or ID, or null to auto-detect Page + * @param Field|string $field Field object or name + * @param int $id Comment ID * @return Comment|null * */ public function getCommentByID($page, $field, $id) { - if(!is_object($page)) $page = $this->wire('pages')->get((int) $page); - if(!$page->id) return null; if(empty($id)) return null; - if(!is_object($field)) $field = $this->wire('fields')->get($this->wire('sanitizer')->fieldName($field)); + if($page && !is_object($page)) { + $page = $this->wire('pages')->get((int) $page); + if(!$page->id) return null; + } + if(!is_object($field) && $field) { + $field = $this->wire('fields')->get($this->wire('sanitizer')->fieldName($field)); + } if(!$field || !$field->type instanceof FieldtypeComments) return null; $table = $field->getTable(); - $sql = "SELECT * FROM `$table` WHERE id=:id AND pages_id=:pageID"; + $sql = "SELECT * FROM `$table` WHERE id=:id "; + if($page) $sql .= "AND pages_id=:pageID"; $query = $this->wire('database')->prepare($sql); $query->bindValue(':id', (int) $id, \PDO::PARAM_INT); - $query->bindValue(':pageID', $page->id, \PDO::PARAM_INT); + if($page) $query->bindValue(':pageID', $page->id, \PDO::PARAM_INT); if(!$query->execute()) return null; if(!$query->rowCount()) return null; $data = $query->fetch(\PDO::FETCH_ASSOC); + if(!$page) { + $page = $this->wire('pages')->get((int) $data['pages_id']); + } return $this->makeComment($page, $field, $data); }