/**
  * Returns the root node for a given structure ID, or creates one if it doesn't exist.
  *
  * @param int $structureId
  *
  * @return StructureElementRecord
  */
 private function _getRootElementRecord($structureId)
 {
     if (!isset($this->_rootElementRecordsByStructureId[$structureId])) {
         $elementRecord = StructureElementRecord::model()->roots()->findByAttributes(array('structureId' => $structureId));
         if (!$elementRecord) {
             // Create it
             $elementRecord = new StructureElementRecord();
             $elementRecord->structureId = $structureId;
             $elementRecord->saveNode();
         }
         $this->_rootElementRecordsByStructureId[$structureId] = $elementRecord;
     }
     return $this->_rootElementRecordsByStructureId[$structureId];
 }
 /**
  * Deletes an element(s) by its ID(s).
  *
  * @param int|array $elementIds The element’s ID, or an array of elements’ IDs.
  *
  * @throws \Exception
  * @return bool Whether the element(s) were deleted successfully.
  */
 public function deleteElementById($elementIds)
 {
     if (!$elementIds) {
         return false;
     }
     if (!is_array($elementIds)) {
         $elementIds = array($elementIds);
     }
     $transaction = craft()->db->getCurrentTransaction() === null ? craft()->db->beginTransaction() : null;
     try {
         // Fire an 'onBeforeDeleteElements' event
         $this->onBeforeDeleteElements(new Event($this, array('elementIds' => $elementIds)));
         // First delete any structure nodes with these elements, so NestedSetBehavior can do its thing. We need to
         // go one-by-one in case one of theme deletes the record of another in the process.
         foreach ($elementIds as $elementId) {
             $records = StructureElementRecord::model()->findAllByAttributes(array('elementId' => $elementId));
             foreach ($records as $record) {
                 // If this element still has any children, move them up before the one getting deleted.
                 $children = $record->children()->findAll();
                 foreach ($children as $child) {
                     $child->moveBefore($record);
                 }
                 // Delete this element's node
                 $record->deleteNode();
             }
         }
         // Delete the caches before they drop their elementId relations (passing `false` because there's no chance
         // this element is suddenly going to show up in a new query)
         craft()->templateCache->deleteCachesByElementId($elementIds, false);
         // Now delete the rows in the elements table
         if (count($elementIds) == 1) {
             $condition = array('id' => $elementIds[0]);
             $matrixBlockCondition = array('ownerId' => $elementIds[0]);
             $searchIndexCondition = array('elementId' => $elementIds[0]);
         } else {
             $condition = array('in', 'id', $elementIds);
             $matrixBlockCondition = array('in', 'ownerId', $elementIds);
             $searchIndexCondition = array('in', 'elementId', $elementIds);
         }
         // First delete any Matrix blocks that belong to this element(s)
         $matrixBlockIds = craft()->db->createCommand()->select('id')->from('matrixblocks')->where($matrixBlockCondition)->queryColumn();
         if ($matrixBlockIds) {
             craft()->matrix->deleteBlockById($matrixBlockIds);
         }
         // Delete the elements table rows, which will cascade across all other InnoDB tables
         $affectedRows = craft()->db->createCommand()->delete('elements', $condition);
         // The searchindex table is MyISAM, though
         craft()->db->createCommand()->delete('searchindex', $searchIndexCondition);
         if ($transaction !== null) {
             $transaction->commit();
         }
         return (bool) $affectedRows;
     } catch (\Exception $e) {
         if ($transaction !== null) {
             $transaction->rollback();
         }
         throw $e;
     }
 }
 /**
  * Deletes an element(s) by its ID(s).
  *
  * @param int|array $elementIds The element’s ID, or an array of elements’ IDs.
  *
  * @throws \Exception
  * @return bool Whether the element(s) were deleted successfully.
  */
 public function deleteElementById($elementIds)
 {
     if (!$elementIds) {
         return false;
     }
     if (!is_array($elementIds)) {
         $elementIds = array($elementIds);
     }
     $transaction = craft()->db->getCurrentTransaction() === null ? craft()->db->beginTransaction() : null;
     try {
         // First delete any structure nodes with these elements, so NestedSetBehavior can do its thing. We need to
         // go one-by-one in case one of theme deletes the record of another in the process.
         foreach ($elementIds as $elementId) {
             $records = StructureElementRecord::model()->findAllByAttributes(array('elementId' => $elementId));
             foreach ($records as $record) {
                 $record->deleteNode();
             }
         }
         // Delete the caches before they drop their elementId relations (passing `false` because there's no chance
         // this element is suddenly going to show up in a new query)
         craft()->templateCache->deleteCachesByElementId($elementIds, false);
         // Fire an 'onBeforeDeleteElements' event
         $this->onBeforeDeleteElements(new Event($this, array('elementIds' => $elementIds)));
         // Now delete the rows in the elements table
         if (count($elementIds) == 1) {
             $condition = array('id' => $elementIds[0]);
         } else {
             $condition = array('in', 'id', $elementIds);
         }
         $affectedRows = craft()->db->createCommand()->delete('elements', $condition);
         if ($transaction !== null) {
             $transaction->commit();
         }
         return (bool) $affectedRows;
     } catch (\Exception $e) {
         if ($transaction !== null) {
             $transaction->rollback();
         }
         throw $e;
     }
 }