mirror of
https://github.com/processwire/processwire.git
synced 2025-08-15 11:14:12 +02:00
Various upgrades to the API of comments fields
This commit is contained in:
@@ -5,7 +5,7 @@
|
||||
*
|
||||
* Class that contains an individual comment.
|
||||
*
|
||||
* ProcessWire 3.x, Copyright 2016 by Ryan Cramer
|
||||
* ProcessWire 3.x, Copyright 2020 by Ryan Cramer
|
||||
* https://processwire.com
|
||||
*
|
||||
* @property int $id
|
||||
@@ -27,7 +27,12 @@
|
||||
* @property string $subcode
|
||||
* @property int $upvotes
|
||||
* @property int $downvotes
|
||||
* @property int $stars
|
||||
* @property int $stars
|
||||
* @property-read Comment|null $parent Parent comment when depth is enabled or null if no parent (since 3.0.149)
|
||||
* @property-read CommentArray $parents All parent comments (since 3.0.149)
|
||||
* @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)
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -172,6 +177,13 @@ class Comment extends WireData {
|
||||
$this->set('stars', 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get property
|
||||
*
|
||||
* @param string $key
|
||||
* @return mixed
|
||||
*
|
||||
*/
|
||||
public function get($key) {
|
||||
|
||||
if($key == 'user' || $key == 'createdUser') {
|
||||
@@ -189,6 +201,9 @@ class Comment extends WireData {
|
||||
|
||||
} else if($key == 'parent') {
|
||||
return $this->parent();
|
||||
|
||||
} else if($key == 'parents') {
|
||||
return $this->parents();
|
||||
|
||||
} else if($key == 'children') {
|
||||
return $this->children();
|
||||
@@ -207,6 +222,12 @@ class Comment extends WireData {
|
||||
|
||||
} else if($key == 'textFormatted') {
|
||||
return $this->textFormatted;
|
||||
|
||||
} else if($key == 'depth') {
|
||||
return $this->depth();
|
||||
|
||||
} else if($key === 'loaded') {
|
||||
return $this->loaded;
|
||||
}
|
||||
|
||||
return parent::get($key);
|
||||
@@ -250,6 +271,14 @@ class Comment extends WireData {
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set property
|
||||
*
|
||||
* @param string $key
|
||||
* @param mixed $value
|
||||
* @return self|WireData
|
||||
*
|
||||
*/
|
||||
public function set($key, $value) {
|
||||
|
||||
if(in_array($key, array('id', 'parent_id', 'status', 'flags', 'pages_id', 'created', 'created_users_id'))) {
|
||||
@@ -285,6 +314,11 @@ class Comment extends WireData {
|
||||
if($value < 1) $value = 0;
|
||||
if($value > 5) $value = 5;
|
||||
}
|
||||
|
||||
if($key == 'parent_id' && parent::get('parent_id') != $value) {
|
||||
// reset a cached parent value, if present
|
||||
$this->_parent = null;
|
||||
}
|
||||
|
||||
return parent::set($key, $value);
|
||||
}
|
||||
@@ -355,26 +389,71 @@ class Comment extends WireData {
|
||||
public function gravatar($rating = 'g', $imageset = 'mm', $size = 80) {
|
||||
return self::getGravatar($this->email, $rating, $imageset, $size);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set Page that this Comment belongs to
|
||||
*
|
||||
* @param Page $page
|
||||
*
|
||||
*/
|
||||
public function setPage(Page $page) {
|
||||
$this->page = $page;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set Field that this Comment belongs to
|
||||
*
|
||||
* @param Field $field
|
||||
*
|
||||
*/
|
||||
public function setField(Field $field) {
|
||||
$this->field = $field;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get Page that this Comment belongs to
|
||||
*
|
||||
* @return null|Page
|
||||
*
|
||||
*/
|
||||
public function getPage() {
|
||||
return $this->page;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Field that this Comment belongs to
|
||||
*
|
||||
* @return null|CommentField
|
||||
*
|
||||
*/
|
||||
public function getField() {
|
||||
return $this->field;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set whether Comment is fully loaded and ready for use
|
||||
*
|
||||
* To get loaded state access the $loaded property of the Comment object.
|
||||
*
|
||||
* #pw-internal
|
||||
*
|
||||
* @param bool $loaded
|
||||
*
|
||||
*/
|
||||
public function setIsLoaded($loaded) {
|
||||
$this->loaded = $loaded ? true : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current comment depth
|
||||
*
|
||||
* @return int
|
||||
* @since 3.0.149
|
||||
*
|
||||
*/
|
||||
public function depth() {
|
||||
return count($this->parents());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the parent comment, if applicable
|
||||
@@ -384,11 +463,10 @@ class Comment extends WireData {
|
||||
*/
|
||||
public function parent() {
|
||||
if(!is_null($this->_parent)) return $this->_parent;
|
||||
$field = $this->getField();
|
||||
if(!$field->depth) return null;
|
||||
$parent_id = $this->parent_id;
|
||||
if(!$parent_id) return null;
|
||||
$comments = $this->getPage()->get($field->name);
|
||||
$field = $this->getField();
|
||||
$comments = $this->getPage()->get($field->name); // no getPageComments() call intentional
|
||||
$parent = null;
|
||||
foreach($comments as $c) {
|
||||
if($c->id != $parent_id) continue;
|
||||
@@ -399,6 +477,25 @@ class Comment extends WireData {
|
||||
return $parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get CommentArray of all parent comments for this one
|
||||
*
|
||||
* Order is closest parent to furthest parent
|
||||
*
|
||||
* @return CommentArray
|
||||
* @since 3.0.149
|
||||
*
|
||||
*/
|
||||
public function parents() {
|
||||
$parents = $this->getPageComments()->makeNew();
|
||||
$parent = $this->parent();
|
||||
while($parent && $parent->id) {
|
||||
$parents->add($parent);
|
||||
$parent = $parent->parent();
|
||||
}
|
||||
return $parents;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return children comments, if applicable
|
||||
*
|
||||
@@ -407,10 +504,11 @@ class Comment extends WireData {
|
||||
*/
|
||||
public function children() {
|
||||
/** @var CommentArray $comments */
|
||||
$comments = $this->getPageComments();
|
||||
$children = $comments->makeNew();
|
||||
// $comments = $this->getPageComments();
|
||||
$page = $this->getPage();
|
||||
$field = $this->getField();
|
||||
$comments = $this->getPage()->get($field->name);
|
||||
$children = $comments->makeNew();
|
||||
if($page) $children->setPage($this->getPage());
|
||||
if($field) $children->setField($this->getField());
|
||||
$id = $this->id;
|
||||
@@ -422,7 +520,40 @@ class Comment extends WireData {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get array that holds all the comments for the current Page/Field
|
||||
* Does this comment have the given child comment?
|
||||
*
|
||||
* @param int|Comment $comment Comment or Comment ID
|
||||
* @param bool $recursive Check all descending children recursively? Use false to check only direct children. (default=true)
|
||||
* @return bool
|
||||
* @since 3.0.149
|
||||
*
|
||||
*/
|
||||
public function hasChild($comment, $recursive = true) {
|
||||
|
||||
$id = $comment instanceof Comment ? $comment->id : (int) $comment;
|
||||
$has = false;
|
||||
$children = $this->children();
|
||||
|
||||
// direct children
|
||||
foreach($children as $child) {
|
||||
if($child->id == $id) $has = true;
|
||||
if($has) break;
|
||||
}
|
||||
|
||||
if($has || !$recursive) return $has;
|
||||
|
||||
// recursive children
|
||||
foreach($children as $child) {
|
||||
/** @var Comment $child */
|
||||
if($child->hasChild($id, true)) $has = true;
|
||||
if($has) break;
|
||||
}
|
||||
|
||||
return $has;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get CommentArray that holds all the comments for the current Page/Field
|
||||
*
|
||||
* #pw-internal
|
||||
*
|
||||
@@ -431,11 +562,31 @@ class Comment extends WireData {
|
||||
*
|
||||
*/
|
||||
public function getPageComments($autoDetect = true) {
|
||||
if($autoDetect && !$this->pageComments) {
|
||||
$field = $this->getField();
|
||||
$this->pageComments = $this->getPage()->get($field->name);
|
||||
|
||||
$pageComments = $this->pageComments;
|
||||
$page = $this->getPage();
|
||||
$field = $this->getField();
|
||||
|
||||
if($pageComments && $autoDetect) {
|
||||
// check if the CommentsArray doesn't share the same Page/Field as the Comment
|
||||
// this could be the case if CommentsArray was from search results rather than Page value
|
||||
$pageCommentsPage = $pageComments->getPage();
|
||||
$pageCommentsField = $pageComments->getField();
|
||||
if($page && $pageCommentsPage && "$page" !== "$pageCommentsPage") {
|
||||
$pageComments = null;
|
||||
} else if($field && $pageCommentsField && "$field" !== "$pageCommentsField") {
|
||||
$pageComments = null;
|
||||
}
|
||||
}
|
||||
return $this->pageComments;
|
||||
|
||||
if(!$pageComments && $autoDetect) {
|
||||
if($page && $field) {
|
||||
$pageComments = $page->get($field->name);
|
||||
$this->pageComments = $pageComments;
|
||||
}
|
||||
}
|
||||
|
||||
return $pageComments;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -508,6 +659,8 @@ class Comment extends WireData {
|
||||
/**
|
||||
* Return URL to edit comment
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
*/
|
||||
public function editUrl() {
|
||||
if(!$this->page || !$this->page->id) return '';
|
||||
|
@@ -324,6 +324,29 @@ class CommentArray extends PaginatedArray implements WirePaginatable {
|
||||
parent::trackAdd($item, $key);
|
||||
if(!$item->getPageComments(false)) $item->setPageComments($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Does this CommentArray have the given Comment (or comment ID)?
|
||||
*
|
||||
* Note: this method is very specific in purpose, accepting only a Comment object or ID.
|
||||
* You can use the has() method for more flexibility.
|
||||
*
|
||||
* @param Comment|int $comment
|
||||
* @return bool
|
||||
* @since 3.0.149
|
||||
* @see WireArray::has()
|
||||
*
|
||||
*/
|
||||
public function hasComment($comment) {
|
||||
$commentID = $comment instanceof Comment ? $comment->id : (int) $comment;
|
||||
$has = false;
|
||||
foreach($this as $item) {
|
||||
if($item->id !== $commentID) continue;
|
||||
$has = true;
|
||||
break;
|
||||
}
|
||||
return $has;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@@ -5,8 +5,28 @@
|
||||
*
|
||||
* Custom “Field” class for Comments fields.
|
||||
*
|
||||
* ProcessWire 3.x, Copyright 2019 by Ryan Cramer
|
||||
* ProcessWire 3.x, Copyright 2020 by Ryan Cramer
|
||||
* https://processwire.com
|
||||
*
|
||||
* @property int $moderate
|
||||
* @property int|bool $redirectAfterPost
|
||||
* @property int|bool $quietSave
|
||||
* @property string $notificationEmail
|
||||
* @property string $fromEmail
|
||||
* @property int $notifySpam
|
||||
* @property int $useNotify See Comment::flagNotify* constants
|
||||
* @property int|bool $useAkismet
|
||||
* @property int $deleteSpamDays
|
||||
* @property int $depth
|
||||
* @property int|bool $sortNewest
|
||||
* @property int|bool $useWebsite
|
||||
* @property string $dateFormat
|
||||
* @property int $useVotes
|
||||
* @property int $useStars
|
||||
* @property string $useGravatar
|
||||
* @property int $schemaVersion
|
||||
*
|
||||
* @todo Some more methods from FieldtypeComments can be moved into this class
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -98,6 +118,131 @@ class CommentField extends Field {
|
||||
return $this->getFieldtype()->voteComment($page, $this, $comment, $up);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow given Comment to have given parent comment?
|
||||
*
|
||||
* @param Comment $comment
|
||||
* @param Comment|int $parent
|
||||
* @param bool $verbose Report reason why not to standard errors? (default=false)
|
||||
* @return bool
|
||||
* @since 3.0.149
|
||||
*
|
||||
*/
|
||||
public function allowCommentParent(Comment $comment, $parent, $verbose = false) {
|
||||
|
||||
$parentID = $parent instanceof Comment ? (int) $parent->id : (int) $parent;
|
||||
if($parentID === 0) return true; // comment with no parent is always allowed
|
||||
|
||||
$error = "Comment $comment->id cannot be reply-to comment $parentID — ";
|
||||
$commentField = $comment->getField();
|
||||
$commentPage = $comment->getPage();
|
||||
|
||||
if(!$commentField) $commentField = $this;
|
||||
|
||||
if("$commentField" !== "$this") {
|
||||
if($verbose) $this->error("$error Comments cannot be moved between fields ($commentField != $this)");
|
||||
return false;
|
||||
}
|
||||
|
||||
if($parentID == $comment->id) {
|
||||
if($verbose) $this->error("$error Comment cannot be its own parent");
|
||||
return false;
|
||||
}
|
||||
|
||||
$maxDepth = (int) $this->get('depth');
|
||||
if(!$maxDepth) {
|
||||
if($verbose) $this->error("$error Comment depth is not enabled in field settings");
|
||||
return false;
|
||||
}
|
||||
|
||||
// determine if current page even has the requested parent comment
|
||||
$parentComment = false; /** @var bool|Comment $parentComment */
|
||||
$pageComments = $commentPage ? $commentPage->get($commentField->name) : array();
|
||||
foreach($pageComments as $pageComment) {
|
||||
if($pageComment->id === $parentID) $parentComment = $pageComment;
|
||||
if($parentComment) break;
|
||||
}
|
||||
// if($parentComment) $this->message("Found parent comment $parentComment on page " . $comment->getPage());
|
||||
|
||||
// if comment is not present here at all, do not allow as a parent
|
||||
if(!$parentComment) {
|
||||
if($verbose) $this->error("$error Page $commentPage does not have parent comment $parentID");
|
||||
return false;
|
||||
}
|
||||
|
||||
// if depth would exceed max allowed depth, comment not allowed
|
||||
if($parentComment->depth() >= $maxDepth) {
|
||||
if($verbose) $this->error("$error Exceeds max allowed depth setting ($maxDepth)");
|
||||
return false;
|
||||
}
|
||||
|
||||
// if this comment already has the given one as a child, it cannot be its parent
|
||||
if($comment->hasChild($parentID, true)) {
|
||||
if($verbose) $this->error("$error Comment $parentID is already a child of comment $comment->id");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow given comment to live on given page?
|
||||
*
|
||||
* @param Comment $comment
|
||||
* @param Page $page
|
||||
* @param bool $verbose Report reason why not to standard errors? (default=false)
|
||||
* @return bool
|
||||
* @since 3.0.149
|
||||
*
|
||||
*/
|
||||
public function allowCommentPage(Comment $comment, Page $page, $verbose = false) {
|
||||
$error = "Comment $comment->id cannot be on page $page->id — ";
|
||||
|
||||
// check if page has the current comment field
|
||||
$commentField = $comment->getField();
|
||||
if(!$commentField) $commentField = $this;
|
||||
if(!$page->hasField($commentField)) {
|
||||
if($verbose) $this->error("$error Page does not have field: $commentField");
|
||||
return false;
|
||||
}
|
||||
|
||||
// if comment is already assigned to the Page then it is allowed
|
||||
$commentPage = $comment->getPage();
|
||||
if($commentPage && $commentPage->id === $page->id) return true;
|
||||
|
||||
// check if comment has a parent comment
|
||||
$parentID = $comment->parent_id;
|
||||
if($parentID) {
|
||||
$pageComments = $page->get($commentField->name);
|
||||
if(!$pageComments || !$pageComments->hasComment($parentID)) {
|
||||
if($verbose) $this->error("$error Comment has parent comment $parentID which does not exist on page $page->id");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* May the given comment be deleted?
|
||||
*
|
||||
* @param Comment $comment
|
||||
* @return bool
|
||||
*
|
||||
*/
|
||||
public function allowDeleteComment(Comment $comment) {
|
||||
$children = $comment->children();
|
||||
if(!$children->count()) return true;
|
||||
$allow = true;
|
||||
foreach($children as $child) {
|
||||
if($child->id > 0 && $child->status < Comment::statusDelete) {
|
||||
$allow = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return $allow;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return FieldtypeComments|Fieldtype
|
||||
*
|
||||
|
@@ -1289,7 +1289,6 @@ class FieldtypeComments extends FieldtypeMulti {
|
||||
$pageID = $row['pages_id'];
|
||||
if(isset($commentPages[$pageID])) {
|
||||
$page = $commentPages[$pageID];
|
||||
$comment->setPage($commentPages[$pageID]);
|
||||
} else {
|
||||
$page = $this->wire('pages')->get((int) $pageID);
|
||||
$commentPages[$page->id] = $page;
|
||||
|
Reference in New Issue
Block a user