/src/elements/db/CommentQuery.php

https://github.com/engram-design/Comments · PHP · 347 lines · 273 code · 61 blank · 13 comment · 33 complexity · d8f245e57e55091ab8f6946527c89ddc MD5 · raw file

  1. <?php
  2. namespace verbb\comments\elements\db;
  3. use verbb\comments\Comments;
  4. use verbb\comments\elements\Comment;
  5. use Craft;
  6. use craft\base\ElementInterface;
  7. use craft\db\Query;
  8. use craft\db\Table;
  9. use craft\elements\db\ElementQuery;
  10. use craft\helpers\ArrayHelper;
  11. use craft\helpers\Db;
  12. use craft\models\Section;
  13. class CommentQuery extends ElementQuery
  14. {
  15. // Public Properties
  16. // =========================================================================
  17. public $withStructure = true;
  18. public $ownerId;
  19. public $ownerSiteId;
  20. public $userId;
  21. public $status;
  22. public $name;
  23. public $email;
  24. public $comment;
  25. public $url;
  26. public $ipAddress;
  27. public $userAgent;
  28. public $commentDate;
  29. public $parentId;
  30. public $ownerType;
  31. public $ownerSectionId;
  32. public $ownerSection;
  33. public $isFlagged;
  34. // Public Methods
  35. // =========================================================================
  36. public function __construct($elementType, array $config = [])
  37. {
  38. // Default status
  39. if (!isset($config['status'])) {
  40. $config['status'] = Comments::$plugin->getSettings()->defaultQueryStatus;
  41. }
  42. parent::__construct($elementType, $config);
  43. }
  44. public function __set($name, $value)
  45. {
  46. switch ($name) {
  47. case 'ownerSection':
  48. $this->ownerSection($value);
  49. break;
  50. default:
  51. parent::__set($name, $value);
  52. }
  53. }
  54. public function ownerType($value)
  55. {
  56. $this->ownerType = $value;
  57. return $this;
  58. }
  59. public function owner(ElementInterface $owner)
  60. {
  61. $this->ownerId = $owner->id;
  62. $this->siteId = $owner->siteId;
  63. return $this;
  64. }
  65. public function ownerId($value)
  66. {
  67. $this->ownerId = $value;
  68. return $this;
  69. }
  70. public function ownerSiteId($value)
  71. {
  72. $this->ownerSiteId = $value;
  73. if ($value && strtolower($value) !== ':empty:') {
  74. // A block will never exist in a site that is different than its ownerSiteId,
  75. // so let's set the siteId param here too.
  76. $this->siteId = (int)$value;
  77. }
  78. return $this;
  79. }
  80. public function ownerSite($value)
  81. {
  82. if ($value instanceof Site) {
  83. $this->ownerSiteId($value->id);
  84. } else {
  85. $site = Craft::$app->getSites()->getSiteByHandle($value);
  86. if (!$site) {
  87. throw new Exception('Invalid site handle: ' . $value);
  88. }
  89. $this->ownerSiteId($site->id);
  90. }
  91. return $this;
  92. }
  93. public function ownerSectionId($value)
  94. {
  95. $this->ownerSectionId = $value;
  96. return $this;
  97. }
  98. public function ownerSection($value)
  99. {
  100. if ($value instanceof Section) {
  101. $this->ownerSectionId = $value->id;
  102. } else if ($value !== null) {
  103. $this->ownerSectionId = (new Query())
  104. ->select(['id'])
  105. ->from([Table::SECTIONS])
  106. ->where(Db::parseParam('handle', $value))
  107. ->column();
  108. } else {
  109. $this->ownerSectionId = null;
  110. }
  111. return $this;
  112. }
  113. public function userId($value)
  114. {
  115. $this->userId = $value;
  116. return $this;
  117. }
  118. public function status($value)
  119. {
  120. $this->status = $value;
  121. return $this;
  122. }
  123. public function name($value)
  124. {
  125. $this->name = $value;
  126. return $this;
  127. }
  128. public function email($value)
  129. {
  130. $this->email = $value;
  131. return $this;
  132. }
  133. public function comment($value)
  134. {
  135. $this->comment = $value;
  136. return $this;
  137. }
  138. public function url($value)
  139. {
  140. $this->url = $value;
  141. return $this;
  142. }
  143. public function ipAddress($value)
  144. {
  145. $this->ipAddress = $value;
  146. return $this;
  147. }
  148. public function userAgent($value)
  149. {
  150. $this->userAgent = $value;
  151. return $this;
  152. }
  153. public function commentDate($value)
  154. {
  155. $this->commentDate = $value;
  156. return $this;
  157. }
  158. public function isFlagged($value)
  159. {
  160. $this->isFlagged = $value;
  161. return $this;
  162. }
  163. public function populate($rows)
  164. {
  165. $results = parent::populate($rows);
  166. // Store the comment IDs we're fetching, so we can use them later in render functions
  167. // to limit DB queries to just this collection of comments (votes, flags.
  168. // But - because we can't rely on getting child comments this way, do another query by the owner element
  169. // so we can be sure we're fetching all the comments for the page.
  170. $ownerId = $results[0]['ownerId'] ?? null;
  171. $ownerSiteId = $results[0]['ownerSiteId'] ?? null;
  172. if ($ownerId && $ownerSiteId) {
  173. $commentIds = (new Query())
  174. ->select('id')
  175. ->from('{{%comments_comments}}')
  176. ->where(['ownerId' => $ownerId, 'ownerSiteId' => $ownerSiteId])
  177. ->column();
  178. Comments::$plugin->getRenderCache()->setCommentIds($commentIds);
  179. }
  180. return $results;
  181. }
  182. protected function beforePrepare(): bool
  183. {
  184. $this->joinElementTable('comments_comments');
  185. $this->query->select([
  186. 'comments_comments.id',
  187. 'comments_comments.ownerId',
  188. 'comments_comments.ownerSiteId',
  189. 'comments_comments.userId',
  190. 'comments_comments.status',
  191. 'comments_comments.name',
  192. 'comments_comments.email',
  193. 'comments_comments.url',
  194. 'comments_comments.comment',
  195. 'comments_comments.ipAddress',
  196. 'comments_comments.userAgent',
  197. 'comments_comments.commentDate',
  198. ]);
  199. if ($this->ownerId) {
  200. $this->subQuery->andWhere(Db::parseParam('comments_comments.ownerId', $this->ownerId));
  201. }
  202. if ($this->ownerSiteId) {
  203. $this->subQuery->andWhere(Db::parseParam('comments_comments.ownerSiteId', $this->ownerSiteId));
  204. }
  205. if ($this->userId) {
  206. $this->subQuery->andWhere(Db::parseParam('comments_comments.userId', $this->userId));
  207. }
  208. if ($this->status) {
  209. $this->subQuery->andWhere(Db::parseParam('comments_comments.status', $this->status));
  210. }
  211. if ($this->name) {
  212. $this->subQuery->andWhere(Db::parseParam('comments_comments.name', $this->name));
  213. }
  214. if ($this->email) {
  215. $this->subQuery->andWhere(Db::parseParam('comments_comments.email', $this->email));
  216. }
  217. if ($this->comment) {
  218. $this->subQuery->andWhere(Db::parseParam('comments_comments.comment', $this->comment));
  219. }
  220. if ($this->url) {
  221. $this->subQuery->andWhere(Db::parseParam('comments_comments.url', $this->url));
  222. }
  223. if ($this->ipAddress) {
  224. $this->subQuery->andWhere(Db::parseParam('comments_comments.ipAddress', $this->ipAddress));
  225. }
  226. if ($this->userAgent) {
  227. $this->subQuery->andWhere(Db::parseParam('comments_comments.userAgent', $this->userAgent));
  228. }
  229. if ($this->commentDate) {
  230. $this->subQuery->andWhere(Db::parseDateParam('comments_comments.commentDate', $this->commentDate));
  231. }
  232. if ($this->isFlagged) {
  233. $this->subQuery->innerJoin('{{%comments_flags}} comments_flags', '[[comments_comments.id]] = [[comments_flags.commentId]]');
  234. }
  235. if ($this->ownerType) {
  236. $this->subQuery->innerJoin('{{%elements}} ownerElements', '[[comments_comments.ownerId]] = [[ownerElements.id]]');
  237. $this->subQuery->andWhere(Db::parseParam('ownerElements.type', $this->ownerType));
  238. }
  239. if ($this->ownerSection) {
  240. $this->subQuery->innerJoin('{{%elements}} ownerElements', '[[comments_comments.ownerId]] = [[ownerElements.id]]');
  241. $this->subQuery->andWhere(Db::parseParam('ownerElements.sectionId', $this->ownerSectionId));
  242. }
  243. if ($this->_orderByVotes()) {
  244. $this->subQuery->leftJoin('{{%comments_votes}} comments_votes', '[[comments_comments.id]] = [[comments_votes.commentId]]');
  245. $this->subQuery->addSelect(['comments_comments.id', '(IFNULL(SUM(comments_votes.upvote), 0) - IFNULL(SUM(comments_votes.downvote), 0)) votes']);
  246. $this->subQuery->addGroupBy(['comments_comments.id', 'structureelements.structureId']);
  247. }
  248. return parent::beforePrepare();
  249. }
  250. protected function statusCondition(string $status)
  251. {
  252. switch ($status) {
  253. case Comment::STATUS_APPROVED:
  254. return [
  255. 'comments_comments.status' => Comment::STATUS_APPROVED,
  256. ];
  257. case Comment::STATUS_PENDING:
  258. return [
  259. 'comments_comments.status' => Comment::STATUS_PENDING,
  260. ];
  261. case Comment::STATUS_SPAM:
  262. return [
  263. 'comments_comments.status' => Comment::STATUS_SPAM,
  264. ];
  265. case Comment::STATUS_TRASHED:
  266. return [
  267. 'comments_comments.status' => Comment::STATUS_TRASHED,
  268. ];
  269. default:
  270. return parent::statusCondition($status);
  271. }
  272. }
  273. // Private Methods
  274. // =========================================================================
  275. private function _orderByVotes()
  276. {
  277. if ($this->orderBy) {
  278. if (is_string($this->orderBy)) {
  279. return strstr($this->orderBy, 'votes');
  280. } else if (is_array($this->orderBy)) {
  281. return isset($this->orderBy['votes']);
  282. }
  283. }
  284. return false;
  285. }
  286. }