public function requirePrimaryImage(Errors &$errors, NodeRef $nodeRef, Node &$node) { $element = $nodeRef->getElement(); $schema = $element->getSchema(); if (!PartialUtils::isTagRoleInOutTagsScope($schema, $node->getNodePartials(), '#primary-image')) { // this should only occur during bulk cms actions return; } if ($schema->hasTagDef('#primary-image')) { $primaryImageTag = $node->getOutTag('#primary-image'); $errors->rejectIfEmpty('#primary-image', 'tag', 'Primary Image', $primaryImageTag); } }
public function decreaseRestrictedInPartials($role) { $this->fields['RestrictedInPartials'] = PartialUtils::decreasePartials($this->fields['RestrictedInPartials'], '#' . ltrim($role, '#')); }
public function saveInTags(DatabaseInterface $db, NodeRef $originNodeRef, $recordid, $inPartials = 'fields', array $inTags, $restrictedPartials = '') { if (empty($recordid)) { throw new Exception('Cannot save in tags without recordid'); } TagUtils::validateTags($inTags); $originalRestrictedPartials = $restrictedPartials; $restrictedPartials = PartialUtils::unserializeInPartials($restrictedPartials); if ($restrictedPartials == 'all' || ($x = array_search('all', $restrictedPartials)) !== false) { return false; } // $originNodeRef = $node->getNodeRef(); // $outtable = $this->NodeDBMeta->getOutTagsTable($originNodeRef); $intable = $this->NodeDBMeta->getInTagsTable($originNodeRef); $tableid = $this->NodeDBMeta->getPrimaryKey($originNodeRef); // $now = $this->DateFactory->newStorageDate(); // $schema = $originNodeRef->getElement()->getSchema(); $tagsToDelete = array(); $tagsToUpdate = array(); // remove duplicates from tags foreach ($inTags as $o => $tag) { if ($originNodeRef->getElement()->hasTagDef($tag->getTagRole())) { $tagDef = $originNodeRef->getElement()->getSchema()->getTagDef($tag->getTagRole()); } else { $externalElement = $this->ElementService->getBySlug($tag->getTagElement()); $tagDef = $externalElement->getSchema()->getTagDef($tag->getTagRole()); } $tag->MatchPartial = TagUtils::determineMatchPartial($tagDef, $originNodeRef->getSlug()); $this->Logger->debug('MATCH PARTIAL for [' . $tag->toString() . '] is [' . $tag->MatchPartial->toString() . ']'); if (!$tagDef->isSortable()) { $tag->TagSortOrder = 0; } else { $tag->ShouldMatchSort = true; } foreach ($inTags as $i => $dtag) { if ($o != $i && $tag->matchExact($dtag)) { // error_log("REMOVING DUPE ".$dtag->toString()); unset($inTags[$o]); } } foreach ($restrictedPartials as $partial) { if ($this->TagsHelper->matchPartial($partial, $tag)) { unset($inTags[$o]); } } } $currentInTags = $this->findTags('in', $db, $originNodeRef, $recordid, $inPartials, true, false, $originalRestrictedPartials, $resolveLinkedRecords = false); TagUtils::validateTags($currentInTags, 'in'); foreach ($currentInTags as $k => $tag) { //if($tag->getTagOutID() == false) throw new Exception('Cannot save in tags without TagOutIDs for current tags'); $foundThisTag = false; foreach ($inTags as $k2 => $dtag) { // Get a list of fields that differ between the current tag and the tag to be saved $tagDiff = $tag->diff($dtag, $dtag->ShouldMatchSort); if (empty($tagDiff)) { // remove it from inTags, since it exists already unset($inTags[$k2]); $foundThisTag = true; break; } elseif (count($tagDiff) == 1 && $tagDiff[0] == 'TagSortOrder') { // If the only difference between the tags is sort order, we don't // want to remove the tag and then add it back. Just do an update. // Save the tag to run through updates later. $tag->setTagSortOrder($dtag->getTagSortOrder()); $tagsToUpdate[] = $tag; // Remove it from intags because we don't want it added again unset($inTags[$k2]); $foundThisTag = true; break; } } if (!$foundThisTag) { $tagsToDelete[] = $tag; } } if (empty($tagsToDelete) && empty($inTags) && empty($tagsToUpdate)) { return false; } foreach ($tagsToDelete as $tag) { $this->Logger->debug("Delete {$tag->getTagDirection()} tag: {$tag->toString()}"); // delete corresponding out tag $outElement = $this->ElementService->getBySlug($tag->getTagElement()); $outNodeRef = new NodeRef($outElement, $tag->getTagSlug()); $outtable = $this->NodeDBMeta->getOutTagsTable($outNodeRef); $outtableid = $this->NodeDBMeta->getPrimaryKey($outNodeRef); try { $outrecordid = $this->getRecordIDFromNodeRef($outNodeRef); } catch (NodeException $ne) { continue; } $affectedRows = $this->getConnectionForWrite($outNodeRef)->write("\n DELETE FROM {$db->quoteIdentifier($outtable)} WHERE\n {$outtableid} = {$db->quote($outrecordid)} AND\n ElementID = {$db->quote($originNodeRef->getElement()->getElementID())} AND\n Slug = {$db->quote($originNodeRef->getSlug())} AND\n Role = {$db->quote($tag->getTagRole())} AND\n Value = {$db->quote($tag->getTagValue())}", DatabaseInterface::AFFECTED_ROWS); if ($affectedRows > 0) { $this->NodeEvents->fireTagEvents('outtags', 'remove', $outNodeRef, $originNodeRef, $tag); } $affectedRows = $db->deleteRecord($db->quoteIdentifier($intable), "TagID = {$db->quote($tag['TagID'])}"); if ($affectedRows > 0) { $this->NodeEvents->fireTagEvents('intags', 'remove', $originNodeRef, $outNodeRef, $tag); } } // Tags that only have their sort order changed, do an update on both sides of the tag and fire an sortOrder.edit // event for the side of the tag that is ordered. foreach ($tagsToUpdate as $tag) { $this->Logger->debug("Update {$tag->getTagDirection()} tag: {$tag->toString()}"); // update corresponding out tag $outNodeRef = $tag->TagLinkNodeRef; $outtable = $this->NodeDBMeta->getOutTagsTable($outNodeRef); $outtableid = $this->NodeDBMeta->getPrimaryKey($outNodeRef); try { $outrecordid = $this->getRecordIDFromNodeRef($outNodeRef); } catch (NodeException $ne) { continue; } $updateArray = array('SortOrder' => $tag->getTagSortOrder()); $affectedRows = $db->updateRecord($db->quoteIdentifier($outtable), $updateArray, "{$outtableid} = {$db->quote($outrecordid)} AND\n ElementID = {$db->quote($originNodeRef->getElement()->getElementID())} AND\n Slug = {$db->quote($originNodeRef->getSlug())} AND\n Role = {$db->quote($tag->getTagRole())} AND\n Value = {$db->quote($tag->getTagValue())}"); $affectedRows = $db->updateRecord($db->quoteIdentifier($intable), $updateArray, "TagID = {$db->quote($tag['TagID'])}"); if ($affectedRows > 0) { $this->NodeEvents->fireTagEvents('intags', 'sortOrder.edit', $originNodeRef, $outNodeRef, $tag); } } if (!empty($inTags)) { foreach ($inTags as $inTag) { // if($inTag->getTagSectionID() != 0) // throw new NodeException('Cannot save in tags coming from a section'); $externalElement = $this->ElementService->getBySlug($inTag->getTagElement()); $externalNodeRef = new NodeRef($externalElement, $inTag->getTagSlug()); try { $externalRecordID = $this->getRecordIDFromNodeRef($externalNodeRef); } catch (NodeException $ne) { continue; } if ('' . $externalNodeRef == '' . $originNodeRef) { continue; } $this->Logger->debug("Add {$inTag->getTagDirection()} tag: {$inTag->toString()}"); //$inTagPartial = new TagPartial($inTag); $db = $this->getConnectionForWrite($externalNodeRef); $newTag = new Tag($originNodeRef->getElement()->getSlug(), $originNodeRef->getSlug(), $inTag->getTagRole(), $inTag->getTagValue(), $inTag->getTagValueDisplay()); $newTag->setTagSortOrder($inTag->getTagSortOrder()); // match partial is used to guarantee that only 1 outbound link exists for that element or element/value combo $this->saveOutTags($db, $externalNodeRef, $externalRecordID, $inTag->getMatchPartial()->toString(), array($newTag)); } } return true; }
public function getNodeFilters(NodeQuery $nodeQuery) { $parameters = $nodeQuery->getParameters(); $filterParams = array(); foreach ($parameters as $key => $value) { switch ($key) { case 'Title.firstChar': $filterParams[$key] = strtolower(substr($value, 0, 1)); break; case 'ActiveDate.after': case 'CreationDate.after': $filterParams[$key] = $this->DateFactory->newLocalDate($value); break; case 'ActiveDate.before': case 'CreationDate.before': $filterParams[$key] = $this->DateFactory->newLocalDate($value); break; case 'ActiveDate.start': case 'CreationDate.start': $value = $this->DateFactory->newLocalDate($value); $value->setTime(0, 0, 0); $filterParams[$key] = $value; break; case 'ActiveDate.end': case 'CreationDate.end': $value = $this->DateFactory->newLocalDate($value); $value->setTime(23, 59, 59); $filterParams[$key] = $value; break; case 'Meta.exist': $filterParams[$key] = PartialUtils::unserializeMetaPartials($value); break; case 'OutTags.exist': case 'InTags.exist': $filterParams[$key] = PartialUtils::unserializeOutPartials($value); break; case 'Title.eq': case 'Title.ieq': case 'Title.like': case 'TreeID.childOf': case 'TreeID.eq': case 'TreeID.depth': case 'Status.eq': case 'Status.isActive': case 'Status.all': $filterParams[$key] = $value; break; } } if (!array_key_exists('Status.eq', $filterParams) && !array_key_exists('Status.isActive', $filterParams) && !array_key_exists('Status.all', $filterParams)) { $filterParams['Status.all'] = false; } return $filterParams; }
protected function validateMetaPartials($partials_string, $tags, NodeSchema $schema) { if (empty($partials_string)) { if (count($tags) > 0) { $this->getErrors()->reject("Meta specified, even though none are in scope."); } } else { $partials = PartialUtils::unserializeMetaPartials($partials_string); foreach ($tags as $tag) { if (!$this->metaInScope($schema, $tag, $partials)) { $this->getErrors()->reject("Meta: " . $tag->toString() . ' is out of scope.'); } } } }
public function buildMySQLQuery(DatabaseInterface $db, $tableNodeRef, $table, $tableid, NodeQuery $nodeQuery, $orderObjects, $slugs, $ids = null) { $table = $db->quoteIdentifier($table); $element = $tableNodeRef->getElement(); $schema = $element->getSchema(); $q = new Query(); $q->SELECT('DISTINCT ' . $table . '.' . $tableid . ' as ID', true); $q->SELECT($table . '.Slug'); $mTableC = 1; if ($nodeQuery->hasParameter('OrderByInTag')) { $inParts = explode(' ', $nodeQuery->getParameter('OrderByInTag'), 2); $partials = PartialUtils::unserializeInPartials($inParts[0]); foreach ($partials as $partial) { if ($partial->getTagElement() && $partial->getTagSlug() && $partial->getTagRole()) { $tTable = $db->quoteIdentifier($this->NodeDBMeta->getInTagsTable($tableNodeRef)); $tClause = $this->NodeTagsDAO->getOutTagPartialClause($partial, $db, $tTable); $q->SELECT("OCondTable" . $mTableC . ".SortOrder as OSortOrder{$mTableC}"); $q->JOIN("INNER JOIN {$tTable} as OCondTable{$mTableC} " . str_replace($tTable, 'OCondTable' . $mTableC, " ON {$table}.{$tableid} = {$tTable}.{$tableid} AND {$tClause}")); $direction = array_key_exists(1, $inParts) ? $inParts[1] : 'ASC'; $q->ORDERBY('OCondTable' . $mTableC . '.SortOrder ' . $direction); $mTableC++; } else { throw new NodeException('Invalid OrderByInTag parameter, must be fully qualified TagPartial with element:slug#role'); } } } if ($nodeQuery->hasParameter('OrderByOutTag')) { $outParts = explode(' ', $nodeQuery->getParameter('OrderByOutTag'), 2); $partials = PartialUtils::unserializeOutPartials($outParts[0]); foreach ($partials as $partial) { if ($partial->getTagElement() && $partial->getTagSlug() && $partial->getTagRole()) { $tTable = $db->quoteIdentifier($this->NodeDBMeta->getOutTagsTable($tableNodeRef)); $tClause = $this->NodeTagsDAO->getOutTagPartialClause($partial, $db, $tTable); $q->SELECT("OCondTable" . $mTableC . ".SortOrder as OSortOrder{$mTableC}"); $q->JOIN("INNER JOIN {$tTable} as OCondTable{$mTableC} " . str_replace($tTable, 'OCondTable' . $mTableC, " ON {$table}.{$tableid} = {$tTable}.{$tableid} AND {$tClause}")); $direction = array_key_exists(1, $outParts) ? $outParts[1] : 'ASC'; $q->ORDERBY('OCondTable' . $mTableC . '.SortOrder ' . $direction); $mTableC++; } else { throw new NodeException('Invalid OrderByOutTag parameter, must be fully qualified TagPartial with element:slug#role'); } } } $mTableC = 1; foreach ($orderObjects as $orderObject) { $column = $orderObject->getColumn(); $direction = $orderObject->getDirection(); //if(!in_array($column, array('ID', 'Slug'))) //{ if ($orderObject->isMeta()) { $partial = $orderObject->getOrderByMetaPartial(); $datatype = $orderObject->getOrderByMetaDataType(); $mTable = $this->NodeDBMeta->getMetaTable($tableNodeRef, $datatype); $mTableAlias = $db->quoteIdentifier($mTable . $mTableC++); $mTable = $db->quoteIdentifier($mTable); $mClause = $this->NodeMetaDAO->getMetaPartialClause(new MetaPartial($partial), $datatype, $db, $mTableAlias); $q->SELECT($mTableAlias . '.' . $datatype . 'Value as ' . $column); $q->JOIN('LEFT JOIN ' . $mTable . ' as ' . $mTableAlias . ' ON ' . $table . '.' . $tableid . ' = ' . $mTableAlias . '.' . $tableid . ' AND ' . $mClause); $q->ORDERBY("{$column} {$direction}"); } else { if ($orderObject->isDirectional()) { if (!in_array($orderObject->getColumn(), array('Title', 'Slug', 'SortOrder', 'ActiveDate', 'CreationDate', 'ModifiedDate', 'TreeID'))) { throw new NodeException('Invalid ordering column [' . $orderObject->getColumn() . '], must be Title, Slug, SortOrder, ActiveDate, CreationDate, ModifiedDate, TreeID, or #meta-id'); } if ($orderObject->getColumn() != 'Slug') { $q->SELECT($table . '.' . $orderObject->getColumn()); } $q->ORDERBY("{$table}.{$column} {$direction}"); } } //} } // Add if clause 2/1/2010 by Craig .. Mysql seems to be doing it's job without this secondary sort. if (empty($orderObjects)) { $q->ORDERBY('ID DESC'); } $q->FROM($table); // ID if (!empty($ids)) { if (count($ids) > 1) { $q->WHERE("{$table}.{$tableid} IN (" . $db->joinQuote($ids) . ")"); } else { if (isset($ids[0])) { $q->WHERE("{$table}.{$tableid} = {$db->quote($ids[0])}"); } } } // Slug if (!empty($slugs)) { if (count($slugs) > 1) { $q->WHERE("{$table}.Slug IN (" . $db->joinQuote($slugs) . ")"); } else { if (isset($slugs[0])) { $q->WHERE("{$table}.Slug = {$db->quote($slugs[0])}"); } } } // AlphaIndex if (($alpha = $nodeQuery->getParameter('Title.firstChar')) != null) { if (strtolower($alpha) == '#') { $q->WHERE("(ASCII(LOWER(LEFT({$table}.Title, 1))) < 65) OR (ASCII(LOWER(LEFT({$table}.Title, 1))) BETWEEN 90 AND 97) OR (ASCII(LOWER(LEFT({$table}.Title, 1))) > 122)"); } else { $q->WHERE("LOWER(LEFT({$table}.Title, 1)) = {$db->quote(strtolower($alpha))}"); } } // Title $this->DTOHelper->buildEqualsFilter($db, $q, $nodeQuery, 'Title.ieq', "{$table}.Title"); $this->DTOHelper->buildReplaceFilter($db, $q, $nodeQuery, 'Title.eq', "BINARY {$table}.Title = ?"); // TitleSearch $this->DTOHelper->buildReplaceFilter($db, $q, $nodeQuery, 'Title.like', "{$table}.Title LIKE ?", '%#s%'); // ParentTreeID $this->DTOHelper->buildReplaceFilter($db, $q, $nodeQuery, 'TreeID.childOf', "{$table}.TreeID LIKE ?", "#s%"); // TreeID $this->DTOHelper->buildEqualsFilter($db, $q, $nodeQuery, 'TreeID.eq', "{$table}.TreeID"); // select node by Tree depth (or limit existing selection) if (($treeDepth = $nodeQuery->getParameter('TreeID.depth')) !== null) { $actualDepth = $treeDepth * 4; $q->orWhere("LENGTH({$table}.TreeID) = {$db->quote($actualDepth)}"); } if (($treeid = $nodeQuery->getParameter('TreeID.parentOf')) != null) { $depth = strlen($treeid) / 4; if ($depth == 1) { $q->WHERE('1 = 0'); } else { for ($i = 1; $i < $depth; ++$i) { $ptreeid = substr($treeid, 0, $i * 4); $q->ORWHERE("{$table}.TreeID = {$db->quote($ptreeid)}"); } } } // ActiveAfter // ActiveBefore $this->DTOHelper->buildDateReplaceFilter($db, $q, $nodeQuery, 'ActiveDate.after', "{$table}.ActiveDate > ?"); $this->DTOHelper->buildDateReplaceFilter($db, $q, $nodeQuery, 'ActiveDate.before', "{$table}.ActiveDate <= ?"); $this->DTOHelper->buildDateReplaceFilter($db, $q, $nodeQuery, 'ActiveDate.start', "{$table}.ActiveDate >= ?", 0, 0, 0); $this->DTOHelper->buildDateReplaceFilter($db, $q, $nodeQuery, 'ActiveDate.end', "{$table}.ActiveDate <= ?", 23, 59, 59); // CreatedAfter // CreatedBefore $this->DTOHelper->buildDateReplaceFilter($db, $q, $nodeQuery, 'CreationDate.after', "{$table}.CreationDate > ?"); $this->DTOHelper->buildDateReplaceFilter($db, $q, $nodeQuery, 'CreationDate.before', "{$table}.CreationDate <= ?"); $this->DTOHelper->buildDateReplaceFilter($db, $q, $nodeQuery, 'CreationDate.start', "{$table}.CreationDate >= ?", 0, 0, 0); $this->DTOHelper->buildDateReplaceFilter($db, $q, $nodeQuery, 'CreationDate.end', "{$table}.CreationDate <= ?", 23, 59, 59); // Status if (($status = $nodeQuery->getParameter('Status.eq')) != null) { switch ($status) { case 'published': $q->WHERE("{$table}.Status = 'published'"); break; case 'draft': $q->WHERE("{$table}.Status = 'draft'"); break; case 'deleted': $q->WHERE("{$table}.Status = 'deleted'"); break; default: $q->WHERE("{$table}.Status != 'deleted'"); break; } } else { if ($nodeQuery->getParameter('Status.isActive') !== null && StringUtils::strToBool($nodeQuery->getParameter('Status.isActive')) == true) { $now = $this->DateFactory->newStorageDate(); $q->WHERE("{$table}.Status = 'published' AND {$table}.ActiveDate < {$db->quote($now)}"); } else { if ($nodeQuery->getParameter('Status.all') == null || StringUtils::strToBool($nodeQuery->getParameter('Status.all')) == false) { $q->WHERE("{$table}.Status != 'deleted'"); } } } $metaParams = $this->NodesHelper->getMetaFilters($nodeQuery); $tablect = 0; foreach ($metaParams as $mArgs) { list($full, $name, $operator, $value) = $mArgs; $def = $schema->getMetaDef($name); $datatype = $def->Datatype; $mTable = $db->quoteIdentifier($this->NodeDBMeta->getMetaTable($tableNodeRef, $datatype)); $clause = ' ' . $db->quoteIdentifier($mTable) . '.Name = ' . $db->quote($name) . " AND "; if ($datatype == 'flag') { throw new NodeException('Unable to run meta clause on flag datatype'); } if (in_array($datatype, array('text', 'blob', 'mediumtext', 'mediumblob'))) { throw new NodeException('Query arguments with #' . $name . ' are not supported'); } switch ($operator) { case 'eq': if ($datatype == 'varchar') { $clause .= " BINARY {$db->quoteIdentifier($mTable)}.{$datatype}Value = {$db->quote($value)}"; } else { $clause .= " {$db->quoteIdentifier($mTable)}.{$datatype}Value = {$db->quote($value)}"; } break; case 'ieq': $clause .= " {$db->quoteIdentifier($mTable)}.{$datatype}Value = {$db->quote($value)}"; break; case 'like': $clause .= " {$db->quoteIdentifier($mTable)}.{$datatype}Value LIKE " . $db->quote('%' . $value . '%'); break; case 'before': $d = $this->DateFactory->newLocalDate($value); $clause .= " {$db->quoteIdentifier($mTable)}.{$datatype}Value <= {$db->quote($d)}"; break; case 'after': $d = $this->DateFactory->newLocalDate($value); $clause .= " {$db->quoteIdentifier($mTable)}.{$datatype}Value > {$db->quote($d)}"; break; case 'start': $d = $this->DateFactory->newLocalDate($value); $d->setTime(0, 0, 0); $clause .= " {$db->quoteIdentifier($mTable)}.{$datatype}Value >= {$db->quote($d)}"; break; case 'end': $d = $this->DateFactory->newLocalDate($value); $d->setTime(23, 59, 59); $clause .= " {$db->quoteIdentifier($mTable)}.{$datatype}Value <= {$db->quote($d)}"; break; case 'notEq': if ($datatype == 'varchar') { $clause .= " BINARY {$db->quoteIdentifier($mTable)}.{$datatype}Value != {$db->quote($value)}"; } else { $clause .= " {$db->quoteIdentifier($mTable)}.{$datatype}Value != {$db->quote($value)}"; } break; case 'lessThan': $clause .= " {$db->quoteIdentifier($mTable)}.{$datatype}Value < {$db->quote($value)}"; break; case 'lessThanEq': $clause .= " {$db->quoteIdentifier($mTable)}.{$datatype}Value <= {$db->quote($value)}"; break; case 'greaterThan': $clause .= " {$db->quoteIdentifier($mTable)}.{$datatype}Value > {$db->quote($value)}"; break; case 'greaterThanEq': $clause .= " {$db->quoteIdentifier($mTable)}.{$datatype}Value >= {$db->quote($value)}"; break; /* * case insensitive comparison for #meta.in filtering. */ /* * case insensitive comparison for #meta.in filtering. */ case 'in': $inValues = explode(',', $value); if (count($inValues) > 1) { $clause .= " {$db->quoteIdentifier($mTable)}.{$datatype}Value IN ({$db->joinQuote($inValues)})"; } else { if ($datatype == 'varchar') { $clause .= " BINARY {$db->quoteIdentifier($mTable)}.{$datatype}Value = {$db->quote($value)}"; } else { $clause .= " {$db->quoteIdentifier($mTable)}.{$datatype}Value = {$db->quote($value)}"; } } break; } $tablect++; $q->JOIN("INNER JOIN {$mTable} as CondTable{$tablect} " . str_replace($mTable, 'CondTable' . $tablect, " ON {$table}.{$tableid} = {$mTable}.{$tableid} AND {$clause}")); } // IncludesMeta // if(($im = $nodeQuery->getParameter('Meta.exist')) != NULL ) { // $metas = PartialUtils::unserializeMetaPartials($im); // $conditions = array(); // foreach($metas as $partial) { // $s = $schema->getMetaDef($partial->getMetaName()); // // $datatype = $s->Datatype; // // $mTable = $db->quoteIdentifier($this->NodeDBMeta->getMetaTable($tableNodeRef, $datatype)); // $mClause = $this->NodeMetaDAO->getMetaPartialClause($partial, $datatype, $db, $mTable); // // $conditions[] = "{$table}.{$tableid} IN // (SELECT {$mTable}.{$tableid} // FROM {$mTable} // WHERE ".$mClause.")"; //// $conditions[] = "EXISTS (SELECT 1 FROM {$this->model->getMetaTable()} //// WHERE {$this->model->getMetaTable()}.{$this->model->getTableID()} = {$table}.{$this->model->getTableID()} //// AND ".$partial->getTagClause($this->model->getMetaTable()).")"; // } // if (!empty($conditions)) { // $q->WHERE(join(' OR ', $conditions)); // } // // } // IncludesAllMeta if (($iam = $nodeQuery->getParameter('Meta.exist')) != NULL) { $metas = PartialUtils::unserializeMetaPartials($iam); foreach ($metas as $partial) { $s = $schema->getMetaDef($partial->getMetaName()); $datatype = $s->Datatype; $mTable = $db->quoteIdentifier($this->NodeDBMeta->getMetaTable($tableNodeRef, $datatype)); $mClause = $this->NodeMetaDAO->getMetaPartialClause($partial, $datatype, $db, $mTable); $tablect++; $q->JOIN("INNER JOIN {$mTable} as CondTable{$tablect} " . str_replace($mTable, 'CondTable' . $tablect, " ON {$table}.{$tableid} = {$mTable}.{$tableid} AND {$mClause}")); // $q->WHERE("{$table}.{$tableid} IN // (SELECT {$mTable}.{$tableid} // FROM {$mTable} // WHERE ".$mClause.")"); // $this->db->WHERE("EXISTS (SELECT 1 FROM {$this->model->getMetaTable()} // WHERE {$this->model->getMetaTable()}.{$this->model->getTableID()} = {$table}.{$this->model->getTableID()} // AND ".$partial->getTagClause($this->model->getMetaTable()).")"); } } // IncludesOutTags // if(($iot = $nodeQuery->getParameter('IncludesOutTags')) != NULL ) { // $tags = PartialUtils::unserializeOutPartials($iot); // $conditions = array(); // foreach($tags as $partial) { // $tTable = $db->quoteIdentifier($this->NodeDBMeta->getOutTagsTable($tableNodeRef)); // // // TODO: need to support aspects // // TODO: convert OR clauses into multiple unions // // $tClause = $this->NodeTagsDAO->getOutTagPartialClause($partial, $tableNodeRef->getSite(), $db, $tTable); // // $conditions[] = "{$table}.{$tableid} IN // (SELECT {$tTable}.{$tableid} // FROM {$tTable} // WHERE {$tClause})"; //// $conditions[] = "EXISTS (SELECT 1 FROM {$this->model->getTagsTable()} t2 //// INNER JOIN tags2 ON t2.tagid = tags2.tagid //// WHERE {$table}.{$this->model->getTableID()} = t2.{$this->model->getTableID()} AND //// ".$partial->getTagClause("tags2").")"; // } // if (!empty($conditions)) { // $q->WHERE(join(' OR ', $conditions)); // } // // } // IncludesAllOutTags if (($iaot = $nodeQuery->getParameter('OutTags.exist')) != NULL) { $tags = PartialUtils::unserializeOutPartials($iaot); foreach ($tags as $partial) { $tTable = $db->quoteIdentifier($this->NodeDBMeta->getOutTagsTable($tableNodeRef)); $tClause = $this->NodeTagsDAO->getOutTagPartialClause($partial, $db, $tTable); $tablect++; $q->JOIN("INNER JOIN {$tTable} as CondTable{$tablect} " . str_replace($tTable, 'CondTable' . $tablect, " ON {$table}.{$tableid} = {$tTable}.{$tableid} AND {$tClause}")); // $q->WHERE( "{$table}.{$tableid} IN // (SELECT {$tTable}.{$tableid} // FROM {$tTable} // WHERE {$tClause})" ); // $this->db->WHERE("EXISTS (SELECT 1 FROM {$this->model->getTagsTable()} t2 // INNER JOIN tags2 ON t2.tagid = tags2.tagid // WHERE {$table}.{$this->model->getTableID()} = t2.{$this->model->getTableID()} AND // ".$partial->getTagClause("tags2").")"); } } // IncludesInTags // if(($iit = $nodeQuery->getParameter('IncludesInTags')) != NULL ) { // $tags = PartialUtils::unserializeInPartials($iit); // $conditions = array(); // foreach($tags as $partial) { // $tTable = $db->quoteIdentifier($this->NodeDBMeta->getInTagsTable($tableNodeRef)); // $tClause = $this->NodeTagsDAO->getInTagPartialClause($partial, $tableNodeRef->getElement(), $tableNodeRef->getSite(), $db, $tTable); // // $conditions[] = "{$table}.{$tableid} IN // (SELECT {$tTable}.{$tableid} // FROM {$tTable} // WHERE {$tClause})"; //// $conditions[] = "EXISTS (SELECT 1 FROM {$this->model->getTagsTable()} t2 //// INNER JOIN tags2 ON t2.tagid = tags2.tagid //// WHERE {$table}.{$this->model->getTableID()} = t2.{$this->model->getTableID()} AND //// ".$partial->getTagClause("tags2").")"; // } // if (!empty($conditions)) { // $q->WHERE(join(' OR ', $conditions)); // } // // } // IncludesAllInTags if (($iait = $nodeQuery->getParameter('InTags.exist')) != NULL) { $tags = PartialUtils::unserializeInPartials($iait); foreach ($tags as $partial) { $tTable = $db->quoteIdentifier($this->NodeDBMeta->getInTagsTable($tableNodeRef)); $tClause = $this->NodeTagsDAO->getInTagPartialClause($partial, $tableNodeRef->getElement(), $db, $tTable); $tablect++; $q->JOIN("INNER JOIN {$tTable} as CondTable{$tablect} " . str_replace($tTable, 'CondTable' . $tablect, " ON {$table}.{$tableid} = {$tTable}.{$tableid} AND {$tClause}")); // // $q->WHERE( "{$table}.{$tableid} IN // (SELECT {$tTable}.{$tableid} // FROM {$tTable} // WHERE {$tClause})" ); // $this->db->WHERE("EXISTS (SELECT 1 FROM {$this->model->getTagsTable()} t2 // INNER JOIN tags2 ON t2.tagid = tags2.tagid // WHERE {$table}.{$this->model->getTableID()} = t2.{$this->model->getTableID()} AND // ".$partial->getTagClause("tags2").")"); } } return $q; }
public function saveMeta(DatabaseInterface $db, NodeRef $originNodeRef, $recordid, $metaPartials = 'fields', array $metaTags, $restrictedPartials = '') { if (empty($recordid)) { throw new Exception('Cannot save meta without recordid'); } $originalRestrictedPartials = $restrictedPartials; $restrictedPartials = PartialUtils::unserializeMetaPartials($restrictedPartials); if ($restrictedPartials == 'all' || ($x = array_search('all', $restrictedPartials)) !== false) { return; } MetaUtils::validateMeta($metaTags); // $originNodeRef = $node->getNodeRef(); $tableid = $this->NodeDBMeta->getPrimaryKey($originNodeRef); $now = $this->DateFactory->newStorageDate(); $tagsToDelete = array(); $updatedMeta = array(); $originalMeta = array(); // if($sectionType != null) // { // $schema = $originNodeRef->getElement()->getSchema()->getSectionDef($sectionType); // } else // { $schema = $originNodeRef->getElement()->getSchema(); // } // remove duplicates from meta foreach ($metaTags as $o => &$mtag) { // if($sectionid != 0) // $mtag->setMetaSectionID($sectionid); $metaDef = $schema->getMetaDef($mtag->getMetaName()); $mtag->setMetaStorageDatatype($metaDef->Datatype); $mtag->setMetaValidationDatatype($metaDef->Validation->getDatatype()); foreach ($metaTags as $i => $ddtag) { //if($o != $i && $tag->getMetaName() === $dtag->getMetaName() && $tag->getMetaSectionID() == $dtag->getMetaSectionID()) if ($o != $i && $mtag->getMetaName() === $ddtag->getMetaName()) { // error_log("REMOVING DUPE ".$dtag->toString()); unset($metaTags[$o]); } } foreach ($restrictedPartials as $dPartial) { if (strcmp($dPartial->getMetaName(), $mtag['MetaName']) === 0) { unset($metaTags[$o]); } } } $currentMetaTags = $this->findMeta($db, $originNodeRef, $recordid, $metaPartials, true, $originalRestrictedPartials); // $this->Logger->debug('current meta for ['.$recordid.'] on section ['.$sectionid.']'); // $this->Logger->debug($currentMetaTags); MetaUtils::validateMeta($currentMetaTags); foreach ($currentMetaTags as $k => $tag) { //if($tag->getMetaID() == false) throw new Exception('Cannot save meta without MetaIDs for current meta'); $foundThisTag = false; foreach ($metaTags as $dtag) { //if($tag->getMetaName() === $dtag->getMetaName() && $tag->getMetaSectionID() == $dtag->getMetaSectionID()) if ($tag->getMetaName() === $dtag->getMetaName()) { // error_log("MATCHED ".$dtag->toString() ." TO ".$tag->toString()); // error_log(print_r($dtag, true)); // error_log(print_r($tag, true)); // delete string meta that have no value if (($dtag->getMetaStorageDatatype() == 'text' || $dtag->getMetaStorageDatatype() == 'varchar' || $dtag->getMetaStorageDatatype() == 'blob') && strlen(trim($dtag->getMetaValue())) == 0 || $dtag->getMetaStorageDatatype() == 'flag' && $dtag->getMetaValue() == false || ($dtag->getMetaValidationDatatype() == 'int' || $dtag->getMetaValidationDatatype() == 'float') && $dtag->getMetaValue() === null || in_array($dtag, $updatedMeta)) { // error_log('DELETE: '.$tag); $tagsToDelete[] = $tag; } else { // error_log('UPDATE: '.$tag); $updatedMeta[$tag->getMetaStorageDatatype()][] = $dtag; $originalMeta[$tag->getMetaStorageDatatype()][] = $tag; } $foundThisTag = true; break; } } if (!$foundThisTag) { $tagsToDelete[] = $tag; } } $changedOne = false; $tagIDsToDelete = array(); foreach ($tagsToDelete as $tag) { // log tag deletion // $this->transactionsService->logMetaDelete($element, $recordid, $tag); $table = $this->NodeDBMeta->getMetaTable($originNodeRef, $tag->getMetaStorageDatatype()); $affectedRows = $db->deleteRecord($table, "{$tableid} = {$db->quote($recordid)} AND Name = {$db->quote($tag->getMetaName())}"); if ($affectedRows > 0) { $this->NodeEvents->fireMetaEvents('meta', 'remove', $originNodeRef, $tag); $changedOne = true; } // $tagIDsToDelete[][] = $tag->getMetaID(); } // if(!empty($tagIDsToDelete)){ // foreach($tagIDsToDelete as $datatype => $ids){ // // ; // $deletions = $db->write("DELETE FROM {$db->quoteIdentifier($table)} WHERE MetaID IN (".$db->joinQuote((array)$ids).")", DatabaseInterface::AFFECTED_ROWS); // // } // } foreach ($metaTags as $tag) { $datatype = $tag->getMetaStorageDatatype(); $table = $db->quoteIdentifier($this->NodeDBMeta->getMetaTable($originNodeRef, $datatype)); if (($datatype == 'text' || $datatype == 'varchar' || $datatype == 'blob') && strlen(trim($tag->getMetaValue())) == 0) { continue; } if ($datatype == 'flag' && $tag->getMetaValue() == false) { continue; } if (($tag->getMetaValidationDatatype() == 'int' || $tag->getMetaValidationDatatype() == 'float') && $tag->getMetaValue() === null) { continue; } $datatypeCol = $this->NodeDBMeta->getMetaDatatypeColumn($datatype); if (isset($updatedMeta[$datatype]) && in_array($tag, $updatedMeta[$datatype])) { $tagid = array_search($tag, $updatedMeta[$datatype]); $originalTag = $originalMeta[$datatype][$tagid]; // if this is an integer storage field and the originalvalue is 0 and the new value equates to 0, do no update if (in_array(strtolower($datatypeCol), array('tiny', 'int', 'long', 'float')) && floatVal($originalTag->getMetaValue()) == 0 && floatVal($tag->getMetaValue()) == 0) { continue; } if ($datatype != 'flag' && strcmp('' . $originalTag->getMetaValue(), '' . $tag->getMetaValue()) !== 0) { // update the meta tag $affectedRows = $db->updateRecord($table, array("{$datatypeCol}Value" => $tag->getMetaValue()), "{$tableid} = {$db->quote($recordid)} AND Name = {$db->quote($tag->getMetaName())}"); if ($affectedRows > 0) { $this->NodeEvents->fireMetaEvents('meta', 'update', $originNodeRef, $tag, $originalTag); // if($tag->getMetaValidationDatatype() == 'boolean') // if($tag->getMetaValue() == false) // $this->NodeEvents->fireMetaEvents('meta', 'remove', $originNodeRef, $tag, $originalTag); // else // $this->NodeEvents->fireMetaEvents('meta', 'add', $originNodeRef, $tag, $originalTag); $changedOne = true; } } } else { // insert the meta tag // $newinsert = array( // $tableid => $recordid, // 'Name' => $tag->getMetaName(), // "{$datatype}Value" => $tag->getMetaValue(), // ); try { if ($datatype == 'flag') { $affectedRows = $db->write("INSERT IGNORE INTO {$table} ({$tableid}, Name) Values ({$db->quote($recordid)}, {$db->quote($tag->getMetaName())})", DatabaseInterface::AFFECTED_ROWS); } else { $affectedRows = $db->write("INSERT INTO {$table} ({$tableid}, Name, {$datatypeCol}Value) Values ({$db->quote($recordid)}, {$db->quote($tag->getMetaName())}, {$db->quote($tag->getMetaValue())})", DatabaseInterface::AFFECTED_ROWS); } // $bulkTagInserts[$datatype][] = $newinsert; // $db->insertRecord($table, $newinsert); if ($affectedRows > 0) { $this->NodeEvents->fireMetaEvents('meta', 'add', $originNodeRef, $tag); $changedOne = true; } } catch (SQLDuplicateKeyException $dke) { $where = "{$tableid} = {$db->quote($recordid)} AND Name = {$db->quote($tag->getMetaName())}"; $originalValue = $db->readField("SELECT {$datatypeCol}Value FROM {$table} WHERE {$where} LOCK IN SHARE MODE"); // update the meta tag $affectedRows = $db->updateRecord($table, array("{$datatypeCol}Value" => $tag->getMetaValue()), $where); if ($affectedRows > 0) { $this->NodeEvents->fireMetaEvents('meta', 'update', $originNodeRef, $tag, new Meta($tag->getMetaName(), $originalValue)); $changedOne = true; } } // $this->NodeEvents->fireMetaEvents('meta', 'add', $originNodeRef, $tag); } } // if(!empty($bulkTagInserts)) // foreach($bulkTagInserts as $datatype => $bulkInserts) // $db->bulkInsertRecords($db->quoteIdentifier($this->NodeDBMeta->getMetaTable($originNodeRef, $datatype)), $bulkInserts); return $changedOne; }