Exemple #1
0
 /**
  * Given a Selector string, return the Page objects that match in a PageArray. 
  * 
  * Non-visible pages are excluded unless an include=hidden|unpublished|all mode is specified in the selector string, 
  * or in the $options array. If 'all' mode is specified, then non-accessible pages (via access control) can also be included. 
  *
  * @param string|int|array $selectorString Specify selector string (standard usage), but can also accept page ID or array of page IDs.
  * @param array|string $options Optional one or more options that can modify certain behaviors. May be assoc array or key=value string.
  *	- findOne: boolean - apply optimizations for finding a single page and include pages with 'hidden' status (default: false)
  *	- getTotal: boolean - whether to set returning PageArray's "total" property (default: true except when findOne=true)
  *	- loadPages: boolean - whether to populate the returned PageArray with found pages (default: true). 
  *		The only reason why you'd want to change this to false would be if you only needed the count details from 
  *		the PageArray: getTotal(), getStart(), getLimit, etc. This is intended as an optimization for Pages::count().
  * 		Does not apply if $selectorString argument is an array. 
  *  - caller: string - optional name of calling function, for debugging purposes, i.e. pages.count
  * 	- include: string - Optional inclusion mode of 'hidden', 'unpublished' or 'all'. Default=none. Typically you would specify this 
  * 		directly in the selector string, so the option is mainly useful if your first argument is not a string. 
  * 	- loadOptions: array - Optional assoc array of options to pass to getById() load options.
  * @return PageArray
  *
  */
 public function ___find($selectorString, $options = array())
 {
     if (is_string($options)) {
         $options = Selectors::keyValueStringToArray($options);
     }
     if (is_array($selectorString)) {
         if (ctype_digit(implode('', array_keys($selectorString))) && ctype_digit(implode('', $selectorString))) {
             // if given a regular array of page IDs, we delegate that to getById() method, but with access/visibility control
             return $this->filterListable($this->getById($selectorString), isset($options['include']) ? $options['include'] : '');
         } else {
             // some other type of array/values that we don't yet recognize
             // @todo add support for array selectors, per Selectors::arrayToSelectorString()
             return new PageArray();
         }
     }
     $loadPages = true;
     $loadOptions = isset($options['loadOptions']) && is_array($options['loadOptions']) ? $options['loadOptions'] : array();
     $debug = $this->wire('config')->debug;
     if (array_key_exists('loadPages', $options)) {
         $loadPages = (bool) $options['loadPages'];
     }
     if (!strlen($selectorString)) {
         return new PageArray();
     }
     if ($selectorString === '/' || $selectorString === 'path=/') {
         $selectorString = 1;
     }
     if ($selectorString[0] == '/') {
         // if selector begins with a slash, then we'll assume it's referring to a path
         $selectorString = "path={$selectorString}";
     } else {
         if (strpos($selectorString, ",") === false && strpos($selectorString, "|") === false) {
             // there is just one param. Lets see if we can find a shortcut.
             if (ctype_digit("{$selectorString}") || strpos($selectorString, "id=") === 0) {
                 // if selector is just a number, or a string like "id=123" then we're going to do a shortcut
                 $s = str_replace("id=", '', $selectorString);
                 if (ctype_digit("{$s}")) {
                     $value = $this->getById(array((int) $s), $loadOptions);
                     if (empty($options['findOne'])) {
                         $value = $this->filterListable($value, isset($options['include']) ? $options['include'] : '');
                     }
                     if ($debug) {
                         $this->debugLog('find', $selectorString . " [optimized]", $value);
                     }
                     return $value;
                 }
             }
         }
     }
     if (isset($options['include']) && in_array($options['include'], array('hidden', 'unpublished', 'all'))) {
         $selectorString .= ", include={$options['include']}";
     }
     // see if this has been cached and return it if so
     $pages = $this->getSelectorCache($selectorString, $options);
     if (!is_null($pages)) {
         if ($debug) {
             $this->debugLog('find', $selectorString, $pages . ' [from-cache]');
         }
         return $pages;
     }
     // check if this find has already been executed, and return the cached results if so
     // if(null !== ($pages = $this->getSelectorCache($selectorString, $options))) return clone $pages;
     // if a specific parent wasn't requested, then we assume they don't want results with status >= Page::statusUnsearchable
     // if(strpos($selectorString, 'parent_id') === false) $selectorString .= ", status<" . Page::statusUnsearchable;
     $caller = isset($options['caller']) ? $options['caller'] : 'pages.find';
     $selectors = new Selectors($selectorString);
     $pageFinder = $this->getPageFinder();
     if ($debug) {
         Debug::timer("{$caller}({$selectorString})", true);
     }
     $pagesInfo = $pageFinder->find($selectors, $options);
     // note that we save this pagination state here and set it at the end of this method
     // because it's possible that more find operations could be executed as the pages are loaded
     $total = $pageFinder->getTotal();
     $limit = $pageFinder->getLimit();
     $start = $pageFinder->getStart();
     if ($loadPages) {
         // parent_id is null unless a single parent was specified in the selectors
         $parent_id = $pageFinder->getParentID();
         $idsSorted = array();
         $idsByTemplate = array();
         // organize the pages by template ID
         foreach ($pagesInfo as $page) {
             $tpl_id = $page['templates_id'];
             if (!isset($idsByTemplate[$tpl_id])) {
                 $idsByTemplate[$tpl_id] = array();
             }
             $idsByTemplate[$tpl_id][] = $page['id'];
             $idsSorted[] = $page['id'];
         }
         if (count($idsByTemplate) > 1) {
             // perform a load for each template, which results in unsorted pages
             $unsortedPages = new PageArray();
             foreach ($idsByTemplate as $tpl_id => $ids) {
                 $opt = $loadOptions;
                 $opt['template'] = $this->templates->get($tpl_id);
                 $opt['parent_id'] = $parent_id;
                 $unsortedPages->import($this->getById($ids, $opt));
             }
             // put pages back in the order that the selectorEngine returned them in, while double checking that the selector matches
             $pages = new PageArray();
             foreach ($idsSorted as $id) {
                 foreach ($unsortedPages as $page) {
                     if ($page->id == $id) {
                         $pages->add($page);
                         break;
                     }
                 }
             }
         } else {
             // there is only one template used, so no resorting is necessary
             $pages = new PageArray();
             reset($idsByTemplate);
             $opt = $loadOptions;
             $opt['template'] = $this->templates->get(key($idsByTemplate));
             $opt['parent_id'] = $parent_id;
             $pages->import($this->getById($idsSorted, $opt));
         }
     } else {
         $pages = new PageArray();
     }
     $pages->setTotal($total);
     $pages->setLimit($limit);
     $pages->setStart($start);
     $pages->setSelectors($selectors);
     $pages->setTrackChanges(true);
     if ($loadPages) {
         $this->selectorCache($selectorString, $options, $pages);
     }
     if ($this->config->debug) {
         $this->debugLog('find', $selectorString, $pages);
     }
     if ($debug) {
         $count = $pages->count();
         $note = ($count == $total ? $count : $count . "/{$total}") . " page(s)";
         if ($count) {
             $note .= ": " . $pages->first()->path;
             if ($count > 1) {
                 $note .= " ... " . $pages->last()->path;
             }
         }
         Debug::saveTimer("{$caller}({$selectorString})", $note);
     }
     if ($this->hasHook('found()')) {
         $this->found($pages, array('pageFinder' => $pageFinder, 'pagesInfo' => $pagesInfo, 'options' => $options));
     }
     return $pages;
 }
Exemple #2
0
 /**
 * Given a Selector string, return the Page objects that match in a PageArray. 
 *
 * @param string $selectorString
 * @param array $options 
 		- findOne: apply optimizations for finding a single page and include pages with 'hidden' status
 * @return PageArray
 *
 */
 public function ___find($selectorString, $options = array())
 {
     // TODO selector strings with runtime fields, like url=/about/contact/, possibly as plugins to PageFinder
     if (!strlen($selectorString)) {
         return new PageArray();
     }
     if ($selectorString === '/' || $selectorString === 'path=/') {
         $selectorString = 1;
     }
     if ($selectorString[0] == '/') {
         // if selector begins with a slash, then we'll assume it's referring to a path
         $selectorString = "path={$selectorString}";
     } else {
         if (strpos($selectorString, ",") === false && strpos($selectorString, "|") === false) {
             // there is just one param. Lets see if we can find a shortcut.
             if (ctype_digit("{$selectorString}") || strpos($selectorString, "id=") === 0) {
                 // if selector is just a number, or a string like "id=123" then we're going to do a shortcut
                 $s = str_replace("id=", '', $selectorString);
                 if (ctype_digit("{$s}")) {
                     $page = $this->getById(array((int) $s));
                     $pageArray = new PageArray();
                     $value = $page ? $pageArray->add($page) : $pageArray;
                     if ($this->config->debug) {
                         $this->debugLog('find', $selectorString . " [optimized]", $value);
                     }
                     return $value;
                 }
             }
         }
     }
     // see if this has been cached and return it if so
     $pages = $this->getSelectorCache($selectorString, $options);
     if (!is_null($pages)) {
         if ($this->config->debug) {
             $this->debugLog('find', $selectorString, $pages . ' [from-cache]');
         }
         return $pages;
     }
     // check if this find has already been executed, and return the cached results if so
     // if(null !== ($pages = $this->getSelectorCache($selectorString, $options))) return clone $pages;
     // if a specific parent wasn't requested, then we assume they don't want results with status >= Page::statusUnsearchable
     // if(strpos($selectorString, 'parent_id') === false) $selectorString .= ", status<" . Page::statusUnsearchable;
     $selectors = new Selectors($selectorString);
     $pages = $this->pageFinder->find($selectors, $options);
     // note that we save this pagination state here and set it at the end of this method
     // because it's possible that more find operations could be executed as the pages are loaded
     $total = $this->pageFinder->getTotal();
     $limit = $this->pageFinder->getLimit();
     $start = $this->pageFinder->getStart();
     // parent_id is null unless a single parent was specified in the selectors
     $parent_id = $this->pageFinder->getParentID();
     $idsSorted = array();
     $idsByTemplate = array();
     // organize the pages by template ID
     foreach ($pages as $page) {
         $tpl_id = $page['templates_id'];
         if (!isset($idsByTemplate[$tpl_id])) {
             $idsByTemplate[$tpl_id] = array();
         }
         $idsByTemplate[$tpl_id][] = $page['id'];
         $idsSorted[] = $page['id'];
     }
     if (count($idsByTemplate) > 1) {
         // perform a load for each template, which results in unsorted pages
         $unsortedPages = new PageArray();
         foreach ($idsByTemplate as $tpl_id => $ids) {
             $unsortedPages->import($this->getById($ids, $this->templates->get($tpl_id), $parent_id));
         }
         // put pages back in the order that the selectorEngine returned them in, while double checking that the selector matches
         $pages = new PageArray();
         foreach ($idsSorted as $id) {
             foreach ($unsortedPages as $page) {
                 if ($page->id == $id) {
                     $pages->add($page);
                     break;
                 }
             }
         }
     } else {
         // there is only one template used, so no resorting is necessary
         $pages = new PageArray();
         reset($idsByTemplate);
         $pages->import($this->getById($idsSorted, $this->templates->get(key($idsByTemplate)), $parent_id));
     }
     $pages->setTotal($total);
     $pages->setLimit($limit);
     $pages->setStart($start);
     $pages->setSelectors($selectors);
     $pages->setTrackChanges(true);
     $this->selectorCache($selectorString, $options, $pages);
     if ($this->config->debug) {
         $this->debugLog('find', $selectorString, $pages);
     }
     return $pages;
     //return $pages->filter($selectors);
 }