コード例 #1
0
 public function search(NodeQuery $dto)
 {
     $searchSafe = $dto->getParameter('SearchKeywords');
     $searchRaw = $dto->getParameter('SearchKeywordsRaw') == null ? preg_replace("/[\\(\\)\\/\\*\\[\\]\\?]+/", '', $searchSafe) : $dto->getParameter('SearchKeywordsRaw');
     $searchThreshold = $dto->getParameter('SearchThreshold');
     $maxresults = $dto->getParameter('SearchMaxResults') != null ? $dto->getParameter('SearchMaxResults') : 500;
     $sortCol = $dto->getParameter('SearchSort') != null ? $dto->getParameter('SearchSort') : 'relevance';
     $sortDir = $dto->getParameter('SearchSortDirection') != null ? $dto->getParameter('SearchSortDirection') : 'desc';
     //        $stopwords = array ('/\bof\b/','/\ba\b/','/\band\b/','/\bthe\b/');
     //        $s = str_replace('+','\+',$searchRaw);
     //        $s = preg_replace($stopwords,' ',$s);
     //$s = preg_replace("/\s+/",' ',$s);
     $s = preg_replace("/\\s+/", ' ', $searchRaw);
     // execute query
     $rows = $this->executeIndexQuery($this->getReadConnection(), $dto, $s, $searchSafe, $maxresults);
     if (sizeof($rows) == 0) {
         return $dto;
     }
     $datascore = $this->columnScores();
     $words = StringUtils::wordsTokenized($s);
     $scores = array();
     $sorts = array();
     $resultingNodeRefs = array();
     $preg_s = preg_quote(str_replace(array('*', '+', '-'), '', $s), '/');
     $ct = 0;
     foreach ($rows as $row) {
         $negative_match = FALSE;
         $found = array();
         if ($ct++ > $maxresults) {
             break;
         }
         $score = $row['Score'];
         if (preg_match("/^{$preg_s}/i", $row['Title'])) {
             $score += 10;
         } elseif (sizeof($words) == 1 && preg_match("/\\b" . $preg_s . "/i", $row['Title'])) {
             $score += 5;
         }
         foreach ($datascore as $param => $val) {
             if (!empty($s) && !empty($row[$param]) && preg_match("/\\b" . $preg_s . "\\b/si", " " . $row[$param] . " ")) {
                 $score += $val;
             }
             $m[$param] = 0;
             foreach ($words as $word) {
                 if (preg_match("/^-(.{2,})/", $word, $m) && preg_match("/\\b{$m['1']}\\b/is", $row[$param])) {
                     $negative_match = TRUE;
                 }
                 $preg_word = preg_quote($word, '/');
                 if (!empty($word) && preg_match("/\\b{$preg_word}\\b/si", " " . $row[$param] . " ")) {
                     if (!isset($m[$param])) {
                         $m[$param] = 0;
                     }
                     $m[$param]++;
                     $found[$word] = 1;
                     $score += $val / 2;
                 }
             }
             if (isset($m[$param]) && $m[$param] == sizeof($words)) {
                 $score += $val * 3;
             }
         }
         if (sizeof($found) > 0) {
             $score = $score * (sizeof($found) / sizeof($words));
         }
         $rowElement = $this->ElementService->getByID($row['ElementID']);
         $rowSlug = $row['Slug'];
         $rowNodeRef = new NodeRef($rowElement, $rowSlug);
         $rawscores['' . $rowNodeRef] = $score;
         if (!$negative_match) {
             if (empty($searchThreshold) || $score > $searchThreshold) {
                 $resultingNodeRefs['' . $rowNodeRef] = $rowNodeRef;
                 $scores['' . $rowNodeRef] = $score;
                 $sorts['' . $rowNodeRef] = $sortCol != 'relevance' ? $row[$sortCol] : $score;
             }
         }
     }
     reset($scores);
     if (sizeof($sorts) == 0) {
         return $dto;
     }
     if (strtolower($sortDir) == 'asc') {
         asort($sorts);
     } else {
         arsort($sorts);
     }
     //        $this->Logger->debug($resultingNodeRefs);
     //        $this->Logger->debug($sorts);
     $results = ArrayUtils::arraySortUsingKeys($resultingNodeRefs, array_keys($sorts));
     $dto->setParameter('NodeRefs.in', $results);
     $dto->setParameter('NodeRefs.fullyQualified', true);
     $dto->setOrderBy('NodeRefs');
     $results = $this->NodeService->findAll($dto)->getResults();
     foreach ($results as $key => &$node) {
         $nodeRef = $node['NodeRef'];
         $node['SearchScore'] = $scores['' . $nodeRef];
         //            error_log($node['Title'].' ('.$node['SearchScore'].')');
     }
     //        $keys = array_map('strval', $sorts);
     $dto->setResults($results);
     return $dto;
 }
コード例 #2
0
 /**
  * @throws NodeException
  * @param NodeQuery $nodeQuery
  * @param bool $forceReadWrite
  * @return NodeQuery
  */
 public function findAll(NodeQuery $nodeQuery, $forceReadWrite = false)
 {
     $this->Benchmark->start('findall');
     //        $this->Logger->debug($nodeQuery);
     $this->Events->trigger('Node.findAll', $nodeQuery);
     if ($nodeQuery->getResults() !== null) {
         return $nodeQuery;
     }
     // NODEREFS
     //list($nodeRefs, $nodePartials, $allFullyQualified) = $this->NodeRefService->parseFromNodeQuery($nodeQuery);
     $this->NodeRefService->normalizeNodeQuery($nodeQuery);
     $nodeRefs = $nodeQuery->getParameter('NodeRefs.normalized');
     $nodePartials = $nodeQuery->getParameter('NodePartials.eq');
     $allFullyQualified = $nodeQuery->getParameter('NodeRefs.fullyQualified');
     if (empty($nodeRefs)) {
         return $nodeQuery;
     }
     //        foreach((array)$nodeRefs as $k => $nodeRef)
     //            $this->NodeEvents->fireNodeEvents('find', '', $nodeRef, $nodePartials, $nodeQuery);
     $orderObjects = $this->NodesHelper->getOrderObjects($nodeQuery);
     //        $this->currentOrderingObjects = $orderObjects;
     $co = false;
     if ($nodeQuery->hasParameter('Count.only') && ($co = $nodeQuery->getParameter('Count.only')) != true) {
         throw new NodeException('Count.only parameter must be equal to true');
     }
     $checkPermissions = $nodeQuery->hasParameter('Permissions.check') && $nodeQuery->getParameter('Permissions.check') == true;
     $doCounts = $nodeQuery->isRetrieveTotalRecords() || $co;
     $offset = $nodeQuery->getOffset() != null ? $nodeQuery->getOffset() : 0;
     $limit = $nodeQuery->getLimit();
     $allowDeleted = $nodeQuery->getParameter('Status.all') != null || $nodeQuery->getParameter('Status.eq') == 'deleted';
     if ($allFullyQualified) {
         $this->Logger->debug('RETRIEVING, SORTING, AND FILTERING IN PHP');
         // TODO: limit this to 50 nodes, PHP can't handle more
         $existsNodePartials = $this->NodesHelper->createNodePartialsFromExistsClauses($nodeQuery);
         // RETRIEVAL PHASE
         $resultingRows = $this->NodeMultiGetDAO->multiGet($nodeRefs, $existsNodePartials, $forceReadWrite, $checkPermissions, $allowDeleted);
         // FILTER PHASE
         $resultingRows = $this->NodesHelper->filterNodes($resultingRows, $nodeQuery);
         if ($doCounts) {
             $totalCount = count($resultingRows);
         }
         if (!empty($resultingRows)) {
             // SORTING PHASE
             $resultingRows = $this->NodesHelper->sortNodes($resultingRows, $orderObjects, true);
             // LIMIT/OFFSET PHASE
             $resultingRows = $this->NodesHelper->sliceNodes($resultingRows, $limit, $offset);
         }
     } else {
         $this->Logger->debug('RETRIEVING, SORTING, AND FILTERING IN MySQL');
         $moreThan1Table = false;
         $connectionCouplets = $this->getResolvedConnectionCouplets($nodeRefs, $forceReadWrite);
         $resultingRows = array();
         $queries = array();
         $elements = array();
         $c = 0;
         $totalCount = 0;
         //$query = null;
         //$firstTable = null;
         //$firstTableID = null;
         foreach ($connectionCouplets as $connectionCouplet) {
             $db = $connectionCouplet->getConnection();
             $tableToSlugs = $connectionCouplet->getAttribute('tablesToSlugs');
             //if(is_null($limit) && count($tableToSlugs) > 1)
             //    throw new Exception('Cannot have limitless query across multiple tables');
             foreach ($tableToSlugs as $table => $tableInfo) {
                 extract($tableInfo);
                 //if(!$query)
                 $query = $this->buildMySQLQuery($db, $tableNodeRef, $table, $tableid, $nodeQuery, $orderObjects, $slugs);
                 //if(!$firstTable)
                 //    $firstTable = $table;
                 //if(!$firstTableID)
                 //    $firstTableID = $tableid;
                 $elementid = $element->getElementID();
                 $elements[$elementid] = $element;
                 $queries[] = array('query' => $query, 'elementid' => $elementid, 'tableid' => $tableid, 'table' => $table, 'db' => $db);
                 $tableInfo = null;
             }
             $tableToSlugs = null;
             $connectionCouplet = null;
         }
         $connectionCouplets = null;
         $moreThan1Table = count($queries) > 1;
         $qcount = 1;
         foreach ($queries as $qArgs) {
             extract($qArgs);
             $q = clone $query;
             if ($doCounts) {
                 $cq = clone $q;
                 $cq->clearSelect();
                 $cq->ORDERBY(null);
                 //$cq->select("COUNT({$db->quoteIdentifier($firstTable)}.$firstTableID)");
                 $cq->select("COUNT(DISTINCT {$db->quoteIdentifier($table)}.{$tableid})");
                 $s = (string) $cq;
                 //$s = str_replace($firstTable, $table, $s);
                 //$s = str_replace($firstTableID, $tableid, $s);
                 $totalCount += (int) $db->readField($s);
                 if ($co) {
                     // Counts.only
                     continue;
                 }
             }
             $batchOffset = $moreThan1Table ? 0 : $offset;
             $batchLimit = $moreThan1Table ? $this->nodeDatabaseBatchLimit : $limit;
             while ($batchOffset > -1) {
                 $rows = null;
                 $reorderOnce = false;
                 $q->LIMIT($moreThan1Table && $batchLimit > 1 ? $batchLimit + 1 : $batchLimit);
                 $q->OFFSET($batchOffset);
                 $s = (string) $q;
                 //$s = str_replace($firstTable, $table, $s);
                 //$s = str_replace($firstTableID, $tableid, $s);
                 $rows = $db->readAll($s);
                 if (empty($rows)) {
                     $batchOffset = -1;
                     break;
                 }
                 //                    $this->Benchmark->start('pushrows');
                 foreach ($rows as $k => $row) {
                     if ($batchLimit > 1 && $k > $batchLimit - 1) {
                         break;
                     }
                     $row['ElementID'] = $elementid;
                     // if there is no limit, push all rows
                     // if there is only 1 table to aggregate, push all rows
                     // if the index of the current result set is less than the total needed rows, push
                     if (is_null($limit) || !$moreThan1Table || $c < $limit + $offset) {
                         $row['NodeRef'] = new NodeRef($elements[$row['ElementID']], $row['Slug']);
                         $resultingRows[] = $row;
                         ++$c;
                     } else {
                         if ($k >= $limit + $offset) {
                             // done with this table (element)
                             $batchOffset = -1;
                             break 2;
                         }
                         if (!$reorderOnce) {
                             $reorderOnce = true;
                             $resultingRows = $this->NodesHelper->sortNodes($resultingRows, $orderObjects);
                         }
                         $lastRow = $resultingRows[$c - 1];
                         // if this row is before the last row in the order, add it in
                         if (!$this->NodesHelper->compareNodes($lastRow, $row, $orderObjects)) {
                             $row['NodeRef'] = new NodeRef($elements[$row['ElementID']], $row['Slug']);
                             $resultingRows[] = $row;
                             //++$c;
                             $lastRow = null;
                             // else break, we're done with this table (element)
                         } else {
                             //        error_log('stopped at last: '.$lastRow['Slug'].' '.$lastRow['ActiveDate']);
                             //        error_log('stopped at: '.$row['Slug'].' '.$row['ActiveDate']);
                             $batchOffset = -1;
                             $lastRow = null;
                             break 2;
                         }
                     }
                 }
                 //                    $this->Benchmark->end('pushrows');
                 if (!$moreThan1Table && $offset == 0 || count($rows) < $batchLimit + 1) {
                     $batchOffset = -1;
                 } else {
                     $batchOffset = $batchOffset + $batchLimit;
                 }
             }
             $rows = null;
             if ($qcount > 1 && $offset > 0 && $moreThan1Table && !empty($resultingRows)) {
                 //                    error_log('resorting');
                 //                    error_log('needed total: '.($limit+$offset));
                 $resultingRows = $this->NodesHelper->sortNodes($resultingRows, $orderObjects);
                 $resultingRows = $this->NodesHelper->sliceNodes($resultingRows, $limit + $offset, 0);
                 //                    $resultingRows = array_slice($resultingRows, 0, ($limit+$offset));
                 $c = count($resultingRows);
             }
             ++$qcount;
             $qArgs = null;
         }
         $queries = null;
         if (!empty($resultingRows)) {
             if ($offset == 0 && $moreThan1Table) {
                 $resultingRows = $this->NodesHelper->sortNodes($resultingRows, $orderObjects);
             }
             $resultingRows = $this->NodesHelper->sliceNodes($resultingRows, $limit, $offset, $moreThan1Table && $offset > 0);
         }
     }
     if (!empty($resultingRows)) {
         $resultingNodeRefs = ArrayUtils::arrayMultiColumn($resultingRows, 'NodeRef');
         if ($nodeQuery->hasParameter('NodeRefs.only') && StringUtils::strToBool($nodeQuery->getParameter('NodeRefs.only')) == true) {
             $nodeQuery->setResults($resultingNodeRefs);
         } else {
             $results = $this->NodeMultiGetDAO->multiGet($resultingNodeRefs, $nodePartials, $forceReadWrite, $checkPermissions, true);
             $keys = array_map('strval', $resultingNodeRefs);
             $results = ArrayUtils::arraySortUsingKeys($results, $keys);
             $keys = null;
             $resultingNodeRefs = null;
             $nodeQuery->setResults($results);
         }
     }
     if ($doCounts) {
         $nodeQuery->setTotalRecords($totalCount);
     }
     $this->Benchmark->end('findall');
     return $nodeQuery;
 }