/** * Preps a {@link DbCommand} object for querying for elements, based on a given element criteria. * * @param ElementCriteriaModel &$criteria The element criteria model * @param string &$contentTable The content table that should be joined in. (This variable will * actually get defined by buildElementsQuery(), and is passed by * reference so whatever’s calling the method will have access to its * value.) * @param array &$fieldColumns Info about the content field columns being selected. (This variable * will actually get defined by buildElementsQuery(), and is passed by * reference so whatever’s calling the method will have access to its * value.) * * @return DbCommand|false The DbCommand object, or `false` if the method was able to determine ahead of time that * there’s no chance any elements are going to be found with the given parameters. */ public function buildElementsQuery(&$criteria = null, &$contentTable = null, &$fieldColumns = null) { if (!$criteria instanceof ElementCriteriaModel) { $criteria = $this->getCriteria('Entry', $criteria); } $elementType = $criteria->getElementType(); if (!$elementType->isLocalized()) { // The criteria *must* be set to the primary locale $criteria->locale = craft()->i18n->getPrimarySiteLocaleId(); } else { if (!$criteria->locale) { // Default to the current app locale $criteria->locale = craft()->language; } } // Set up the query // --------------------------------------------------------------------- $query = craft()->db->createCommand()->select('elements.id, elements.type, elements.enabled, elements.archived, elements.dateCreated, elements.dateUpdated, elements_i18n.slug, elements_i18n.uri, elements_i18n.enabled AS localeEnabled')->from('elements elements')->join('elements_i18n elements_i18n', 'elements_i18n.elementId = elements.id')->where('elements_i18n.locale = :locale', array(':locale' => $criteria->locale))->group('elements.id'); if ($elementType->hasContent()) { $contentTable = $elementType->getContentTableForElementsQuery($criteria); if ($contentTable) { $contentCols = 'content.id AS contentId'; if ($elementType->hasTitles()) { $contentCols .= ', content.title'; } // TODO: Replace this with a call to getFieldsForElementsQuery() in 3.0 $fieldColumns = $elementType->getContentFieldColumnsForElementsQuery($criteria); foreach ($fieldColumns as $column) { $contentCols .= ', content.' . $column['column']; } $query->addSelect($contentCols); $query->join($contentTable . ' content', 'content.elementId = elements.id'); $query->andWhere('content.locale = :locale'); } } // Basic element params // --------------------------------------------------------------------- // If the 'id' parameter is set to any empty value besides `null`, don't return anything if ($criteria->id !== null && empty($criteria->id)) { return false; } if ($criteria->id) { $query->andWhere(DbHelper::parseParam('elements.id', $criteria->id, $query->params)); } if ($criteria->archived) { $query->andWhere('elements.archived = 1'); } else { $query->andWhere('elements.archived = 0'); if ($criteria->status) { $statusConditions = array(); $statuses = ArrayHelper::stringToArray($criteria->status); foreach ($statuses as $status) { $status = StringHelper::toLowerCase($status); // Is this a supported status? if (in_array($status, array_keys($elementType->getStatuses()))) { if ($status == BaseElementModel::ENABLED) { $statusConditions[] = 'elements.enabled = 1'; } else { if ($status == BaseElementModel::DISABLED) { $statusConditions[] = 'elements.enabled = 0'; } else { $elementStatusCondition = $elementType->getElementQueryStatusCondition($query, $status); if ($elementStatusCondition) { $statusConditions[] = $elementStatusCondition; } else { if ($elementStatusCondition === false) { return false; } } } } } } if ($statusConditions) { if (count($statusConditions) == 1) { $statusCondition = $statusConditions[0]; } else { array_unshift($statusConditions, 'or'); $statusCondition = $statusConditions; } $query->andWhere($statusCondition); } } } if ($criteria->dateCreated) { $query->andWhere(DbHelper::parseDateParam('elements.dateCreated', $criteria->dateCreated, $query->params)); } if ($criteria->dateUpdated) { $query->andWhere(DbHelper::parseDateParam('elements.dateUpdated', $criteria->dateUpdated, $query->params)); } if ($elementType->hasTitles() && $criteria->title) { $query->andWhere(DbHelper::parseParam('content.title', $criteria->title, $query->params)); } // i18n params // --------------------------------------------------------------------- if ($criteria->slug) { $query->andWhere(DbHelper::parseParam('elements_i18n.slug', $criteria->slug, $query->params)); } if ($criteria->uri) { $query->andWhere(DbHelper::parseParam('elements_i18n.uri', $criteria->uri, $query->params)); } if ($criteria->localeEnabled) { $query->andWhere('elements_i18n.enabled = 1'); } // Relational params // --------------------------------------------------------------------- // Convert the old childOf and parentOf params to the relatedTo param // childOf(element) => relatedTo({ source: element }) // parentOf(element) => relatedTo({ target: element }) if (!$criteria->relatedTo && ($criteria->childOf || $criteria->parentOf)) { $relatedTo = array('and'); if ($criteria->childOf) { $relatedTo[] = array('sourceElement' => $criteria->childOf, 'field' => $criteria->childField); } if ($criteria->parentOf) { $relatedTo[] = array('targetElement' => $criteria->parentOf, 'field' => $criteria->parentField); } $criteria->relatedTo = $relatedTo; } if ($criteria->relatedTo) { $relationParamParser = new ElementRelationParamParser(); $relConditions = $relationParamParser->parseRelationParam($criteria->relatedTo, $query); if ($relConditions === false) { return false; } $query->andWhere($relConditions); // If there's only one relation criteria and it's specifically for grabbing target elements, allow the query // to order by the relation sort order if ($relationParamParser->isRelationFieldQuery()) { $query->addSelect('sources1.sortOrder'); } } // Give field types a chance to make changes // --------------------------------------------------------------------- if ($elementType->hasContent() && $contentTable) { $contentService = craft()->content; $originalFieldColumnPrefix = $contentService->fieldColumnPrefix; // TODO: $fields should already be defined by now in Craft 3.0 $fields = $elementType->getFieldsForElementsQuery($criteria); $extraCriteriaAttributes = $criteria->getExtraAttributeNames(); foreach ($fields as $field) { $fieldType = $field->getFieldType(); if ($fieldType) { // Was this field's parameter set on the criteria model? if (in_array($field->handle, $extraCriteriaAttributes)) { $fieldCriteria = $criteria->{$field->handle}; } else { $fieldCriteria = null; } // Set the field's column prefix on ContentService if ($field->columnPrefix) { $contentService->fieldColumnPrefix = $field->columnPrefix; } $fieldTypeResponse = $fieldType->modifyElementsQuery($query, $fieldCriteria); // Set it back $contentService->fieldColumnPrefix = $originalFieldColumnPrefix; // Need to bail early? if ($fieldTypeResponse === false) { return false; } } } } // Give the element type a chance to make changes // --------------------------------------------------------------------- if ($elementType->modifyElementsQuery($query, $criteria) === false) { return false; } // Structure params // --------------------------------------------------------------------- if ($query->isJoined('structureelements')) { $query->addSelect('structureelements.root, structureelements.lft, structureelements.rgt, structureelements.level'); if ($criteria->ancestorOf) { if (!$criteria->ancestorOf instanceof BaseElementModel) { $criteria->ancestorOf = craft()->elements->getElementById($criteria->ancestorOf, $elementType->getClassHandle(), $criteria->locale); if (!$criteria->ancestorOf) { return false; } } if ($criteria->ancestorOf) { $query->andWhere(array('and', 'structureelements.lft < :ancestorOf_lft', 'structureelements.rgt > :ancestorOf_rgt', 'structureelements.root = :ancestorOf_root'), array(':ancestorOf_lft' => $criteria->ancestorOf->lft, ':ancestorOf_rgt' => $criteria->ancestorOf->rgt, ':ancestorOf_root' => $criteria->ancestorOf->root)); if ($criteria->ancestorDist) { $query->andWhere('structureelements.level >= :ancestorOf_level', array(':ancestorOf_level' => $criteria->ancestorOf->level - $criteria->ancestorDist)); } } } if ($criteria->descendantOf) { if (!$criteria->descendantOf instanceof BaseElementModel) { $criteria->descendantOf = craft()->elements->getElementById($criteria->descendantOf, $elementType->getClassHandle(), $criteria->locale); if (!$criteria->descendantOf) { return false; } } if ($criteria->descendantOf) { $query->andWhere(array('and', 'structureelements.lft > :descendantOf_lft', 'structureelements.rgt < :descendantOf_rgt', 'structureelements.root = :descendantOf_root'), array(':descendantOf_lft' => $criteria->descendantOf->lft, ':descendantOf_rgt' => $criteria->descendantOf->rgt, ':descendantOf_root' => $criteria->descendantOf->root)); if ($criteria->descendantDist) { $query->andWhere('structureelements.level <= :descendantOf_level', array(':descendantOf_level' => $criteria->descendantOf->level + $criteria->descendantDist)); } } } if ($criteria->siblingOf) { if (!$criteria->siblingOf instanceof BaseElementModel) { $criteria->siblingOf = craft()->elements->getElementById($criteria->siblingOf, $elementType->getClassHandle(), $criteria->locale); if (!$criteria->siblingOf) { return false; } } if ($criteria->siblingOf) { $query->andWhere(array('and', 'structureelements.level = :siblingOf_level', 'structureelements.root = :siblingOf_root', 'structureelements.elementId != :siblingOf_elementId'), array(':siblingOf_level' => $criteria->siblingOf->level, ':siblingOf_root' => $criteria->siblingOf->root, ':siblingOf_elementId' => $criteria->siblingOf->id)); if ($criteria->siblingOf->level != 1) { $parent = $criteria->siblingOf->getParent(); if ($parent) { $query->andWhere(array('and', 'structureelements.lft > :siblingOf_lft', 'structureelements.rgt < :siblingOf_rgt'), array(':siblingOf_lft' => $parent->lft, ':siblingOf_rgt' => $parent->rgt)); } else { return false; } } } } if ($criteria->prevSiblingOf) { if (!$criteria->prevSiblingOf instanceof BaseElementModel) { $criteria->prevSiblingOf = craft()->elements->getElementById($criteria->prevSiblingOf, $elementType->getClassHandle(), $criteria->locale); if (!$criteria->prevSiblingOf) { return false; } } if ($criteria->prevSiblingOf) { $query->andWhere(array('and', 'structureelements.level = :prevSiblingOf_level', 'structureelements.rgt = :prevSiblingOf_rgt', 'structureelements.root = :prevSiblingOf_root'), array(':prevSiblingOf_level' => $criteria->prevSiblingOf->level, ':prevSiblingOf_rgt' => $criteria->prevSiblingOf->lft - 1, ':prevSiblingOf_root' => $criteria->prevSiblingOf->root)); } } if ($criteria->nextSiblingOf) { if (!$criteria->nextSiblingOf instanceof BaseElementModel) { $criteria->nextSiblingOf = craft()->elements->getElementById($criteria->nextSiblingOf, $elementType->getClassHandle(), $criteria->locale); if (!$criteria->nextSiblingOf) { return false; } } if ($criteria->nextSiblingOf) { $query->andWhere(array('and', 'structureelements.level = :nextSiblingOf_level', 'structureelements.lft = :nextSiblingOf_lft', 'structureelements.root = :nextSiblingOf_root'), array(':nextSiblingOf_level' => $criteria->nextSiblingOf->level, ':nextSiblingOf_lft' => $criteria->nextSiblingOf->rgt + 1, ':nextSiblingOf_root' => $criteria->nextSiblingOf->root)); } } if ($criteria->positionedBefore) { if (!$criteria->positionedBefore instanceof BaseElementModel) { $criteria->positionedBefore = craft()->elements->getElementById($criteria->positionedBefore, $elementType->getClassHandle(), $criteria->locale); if (!$criteria->positionedBefore) { return false; } } if ($criteria->positionedBefore) { $query->andWhere(array('and', 'structureelements.rgt < :positionedBefore_rgt', 'structureelements.root = :positionedBefore_root'), array(':positionedBefore_rgt' => $criteria->positionedBefore->lft, ':positionedBefore_root' => $criteria->positionedBefore->root)); } } if ($criteria->positionedAfter) { if (!$criteria->positionedAfter instanceof BaseElementModel) { $criteria->positionedAfter = craft()->elements->getElementById($criteria->positionedAfter, $elementType->getClassHandle(), $criteria->locale); if (!$criteria->positionedAfter) { return false; } } if ($criteria->positionedAfter) { $query->andWhere(array('and', 'structureelements.lft > :positionedAfter_lft', 'structureelements.root = :positionedAfter_root'), array(':positionedAfter_lft' => $criteria->positionedAfter->rgt, ':positionedAfter_root' => $criteria->positionedAfter->root)); } } if ($criteria->level || $criteria->depth) { // TODO: 'depth' is deprecated; use 'level' instead. $level = $criteria->level ? $criteria->level : $criteria->depth; $query->andWhere(DbHelper::parseParam('structureelements.level', $level, $query->params)); } } // Search // --------------------------------------------------------------------- if ($criteria->search) { $elementIds = $this->_getElementIdsFromQuery($query); $scoredSearchResults = $criteria->order == 'score'; $filteredElementIds = craft()->search->filterElementIdsByQuery($elementIds, $criteria->search, $scoredSearchResults); // No results? if (!$filteredElementIds) { return array(); } $query->andWhere(array('in', 'elements.id', $filteredElementIds)); if ($scoredSearchResults) { // Order the elements in the exact order that SearchService returned them in $query->order(craft()->db->getSchema()->orderByColumnValues('elements.id', $filteredElementIds)); } } return $query; }
/** * Preps a {@link DbCommand} object for querying for elements, based on a given element criteria. * * @param Venti_CriteriaModel &$criteria The events criteria model * * @return DbCommand|false The DbCommand object, or `false` if the method was able to determine ahead of time that * there’s no chance any elements are going to be found with the given parameters. */ public function buildEventsQuery(Venti_CriteriaModel $criteria) { $elementType = $criteria->getElementType(); if (!$elementType->isLocalized()) { // The criteria *must* be set to the primary locale $criteria->locale = craft()->i18n->getPrimarySiteLocaleId(); } else { if (!$criteria->locale) { // Default to the current app locale $criteria->locale = craft()->language; } } $query = craft()->db->createCommand()->select('venti.startDate, venti.endDate, venti.allDay, venti.isrepeat, venti.eid, venti.eventid, venti.repeat, venti.rRule, venti.summary, elements.id, elements.type, elements.enabled, elements.archived, elements.dateCreated, elements.dateUpdated, elements_i18n.slug, elements_i18n.uri, elements_i18n.enabled AS localeEnabled')->from('venti_events venti')->join('elements elements', 'elements.id = venti.eventid')->join('elements_i18n elements_i18n', 'elements_i18n.elementId = venti.eventid')->where('elements_i18n.locale = :locale', array(':locale' => $criteria->locale))->limit($criteria->limit)->offset($criteria->offset)->order($criteria->order); if ($elementType->hasContent()) { $contentTable = 'content'; if ($contentTable) { $contentCols = 'content.id AS contentId'; if ($elementType->hasTitles()) { $contentCols .= ', content.title'; } $fieldColumns = $this->getContentFieldColumnsForElementsQuery($criteria); foreach ($fieldColumns as $column) { $contentCols .= ', content.' . $column['column']; } $query->addSelect($contentCols); $query->join($contentTable . ' content', 'content.elementId = elements.id'); $query->andWhere('content.locale = :locale'); } } if ($elementType->hasTitles() && $criteria->title) { $query->andWhere(DbHelper::parseParam('content.title', $criteria->title, $query->params)); } if ($criteria->id) { $query->andWhere(DbHelper::parseParam('venti.eventid', $criteria->id, $query->params)); } if ($criteria->eid) { $query->andWhere(DbHelper::parseParam('venti.eid', $criteria->eid, $query->params)); } if ($criteria->isrepeat) { $query->andWhere(DbHelper::parseParam('venti.isrepeat', $criteria->isrepeat, $query->params)); } if ($criteria->startDate) { $query->andWhere(DbHelper::parseDateParam('venti.startDate', $criteria->startDate, $query->params)); } if ($criteria->endDate) { $query->andWhere(DbHelper::parseDateParam('venti.endDate', $criteria->endDate, $query->params)); } if ($criteria->summary) { $query->andWhere(DbHelper::parseParam('venti.summary', $criteria->summary, $query->params)); } if ($criteria->slug) { $query->andWhere(DbHelper::parseParam('elements_i18n.slug', $criteria->slug, $query->params)); } if ($criteria->uri) { $query->andWhere(DbHelper::parseParam('elements_i18n.uri', $criteria->uri, $query->params)); } if ($criteria->localeEnabled) { $query->andWhere('elements_i18n.enabled = 1'); } if ($criteria->dateCreated) { $query->andWhere(DbHelper::parseDateParam('elements.dateCreated', $criteria->dateCreated, $query->params)); } if ($criteria->dateUpdated) { $query->andWhere(DbHelper::parseDateParam('elements.dateUpdated', $criteria->dateUpdated, $query->params)); } if ($criteria->archived) { $query->andWhere('elements.archived = 1'); } else { $query->andWhere('elements.archived = 0'); if ($criteria->status) { $statusConditions = array(); $statuses = ArrayHelper::stringToArray($criteria->status); foreach ($statuses as $status) { $status = StringHelper::toLowerCase($status); // Is this a supported status? if (in_array($status, array_keys($this->getStatuses()))) { if ($status == BaseElementModel::ENABLED) { $statusConditions[] = 'elements.enabled = 1'; } else { if ($status == BaseElementModel::DISABLED) { $statusConditions[] = 'elements.enabled = 0'; } else { $elementStatusCondition = $this->getElementQueryStatusCondition($query, $status); if ($elementStatusCondition) { $statusConditions[] = $elementStatusCondition; } else { if ($elementStatusCondition === false) { return false; } } } } } } if ($statusConditions) { if (count($statusConditions) == 1) { $statusCondition = $statusConditions[0]; } else { array_unshift($statusConditions, 'or'); $statusCondition = $statusConditions; } $query->andWhere($statusCondition); } } } // Relational params // --------------------------------------------------------------------- if ($criteria->relatedTo) { $relationParamParser = new ElementRelationParamParser(); $relConditions = $relationParamParser->parseRelationParam($criteria->relatedTo, $query); if ($relConditions === false) { return false; } $query->andWhere($relConditions); // If there's only one relation criteria and it's specifically for grabbing target elements, allow the query // to order by the relation sort order if ($relationParamParser->isRelationFieldQuery()) { $query->addSelect('sources1.sortOrder'); } } // Search // --------------------------------------------------------------------- if ($criteria->search) { $elementIds = $this->_getElementIdsFromQuery($query); $scoredSearchResults = $criteria->order == 'score'; $filteredElementIds = craft()->search->filterElementIdsByQuery($elementIds, $criteria->search, $scoredSearchResults); // No results? if (!$filteredElementIds) { return array(); } $query->andWhere(array('in', 'venti.eventid', $filteredElementIds)); if ($scoredSearchResults) { // Order the elements in the exact order that SearchService returned them in $query->order(craft()->db->getSchema()->orderByColumnValues('venti.eventid', $filteredElementIds)); } } return $query; }