pietschy avatar pietschy committed 216cb90 Merge

merged

Comments (0)

Files changed (2)

blocks/navigation_builder_block/controller.php

 
     public function on_before_render()
     {
-        if (!empty($this->field_1_link_cID)) {
+        $pageID = $this->field_1_link_cID;
+        if (!empty($pageID)) {
             Loader::model('NavigationBuilder', 'navigation_builder');
             $builder = new NavigationBuilder();
+            $builder->applyDefaultExcludes();
             $builder->setMaxDepth($this->field_2_select_value); // the text values happen to correspond to the int value required.
-            $rootPage = Page::getByID($this->field_1_link_cID);
+            $rootPage = Page::getByID($pageID);
             $navRoot = $builder->build($rootPage);
             $this->set('rootPage', $rootPage);
             $this->set('navRoot', $navRoot);

models/NavigationBuilder.php

 //    private $startDepth = -1;
 
     /** @var array */
+    private $includePageConditions = array();
+    /** @var array */
+    private $excludePageConditions = array();
+    /** @var array */
     private $excludedPaths = array();
 
+
     /** @var TerarpCommonStringHelper $sh $*/
     private $sh;
 
-    private $excludeChildrenCallback = null;
+    private $excludeChildrenCondition = null;
 
     /**
      *
     public function __construct()
     {
         Loader::model('page_list');
-        $this->sh  = Loader::helper("string", "terarp_common");
+        $this->sh = Loader::helper("string", "terarp_common");
+
+        $this->includeCallback = function () {
+            return true;
+        };
     }
 
 
     }
 
     /**
-    * Builds the navigation tree from the specified page.  The method returns an instance
-    * of {@link NavRoot} with {@link NavItem} children populated according to the search.
-    * The NavRoot corresponds to the specified page.
-    *
-    * @param $rootPage Page
-    * @return NavRoot
-    */
+     * Builds the navigation tree from the specified page.  The method returns an instance
+     * of {@link NavRoot} with {@link NavItem} children populated according to the search.
+     * The NavRoot corresponds to the specified page.
+     *
+     * @param $rootPage Page
+     * @return NavRoot
+     */
     public function buildWithRootAsFirstItem($rootPage)
     {
-       $navRoot = $this->buildTree($rootPage);
-       // We have to add the root back in after we've processed the children
-       // or it gets traversed and populated a second time-a...
-       $firstItem = $this->createNavItem($rootPage);
-       $navRoot->insertChild($firstItem);
+        $navRoot = $this->buildTree($rootPage);
+        // We have to add the root back in after we've processed the children
+        // or it gets traversed and populated a second time-a...
+        $firstItem = $this->createNavItem($rootPage);
+        $navRoot->insertChild($firstItem);
 
-       $navRoot->configureActivePathFrom(Page::getCurrentPage());
-       return $navRoot;
+        $navRoot->configureActivePathFrom(Page::getCurrentPage());
+        return $navRoot;
     }
 
-    public function applyDefaultExcludes() {
-        $this->excludeChildrenWhen(function($page) {
+    /**
+     * Applied the default excludes for typical site navigation scenarios.
+     * <ul>
+     *<li>Exclude pages that have <b>exclude_nav</b> set to true</li>
+     *<li>Exclude pages who's ancestor has <b>exclude_children_from_nav</b> set to true</li>
+     *<li>Excludes members pages that are under the path '/members'</li>
+     * </ul>
+     */
+    public function applyDefaultExcludes()
+    {
+        $this->excludeChildrenWhen(function ($page) {
+            /** @var Page $page */
             return $page->getCollectionAttributeValue('exclude_children_from_nav') == true;
         });
+
+        $this->excludePageWhen(function ($page) {
+            /** @var Page $page */
+            return $page->getCollectionAttributeValue('exclude_nav') == true;
+        });
+
+        $this->excludePageWhenPathEquals('/members');
     }
 
-    public function excludeChildrenWhen(Closure $filter)
-    {
-        $this->excludeChildrenCallback = $filter;
-    }
-
-
     private function buildTree($rootPage)
     {
         $navRoot = $this->createNavRoot($rootPage);
         return $navRoot;
     }
 
+    public function includePageWhen($callable)
+    {
+        $this->includePageConditions [] = $callable;
+    }
+
+    public function excludePageWhen($callable)
+    {
+        $this->excludePageConditions [] = $callable;
+    }
+
+    /**
+     * Adds a path path to the list of excludes.  E.g.
+     * <pre>
+     * $builder->excludeIfPathEquals('/members');
+     * </pre>
+     * @param $path
+     * @return void
+     */
+    public function excludePageWhenPathEquals($path)
+    {
+        $this->excludedPaths[] = $path;
+    }
+
+    public function excludeChildrenWhen(Closure $filter)
+    {
+        $this->excludeChildrenCondition = $filter;
+    }
+
+
     /**
      * A recursive method that is the core method responsible for generating the navigation tree.  It
      * calls {@link shouldInclude} to determine if a page should be included in the tree, then calls
      * @param $navItem NavItem the current navItem that is to have it's children populated
      * @return void
      */
-    protected function processChildren($navItem) {
+    protected function processChildren($navItem)
+    {
 
         // this could go into shouldIncludeChildren but I want to
         // be able to override that method with custom logic without
         // accidentally missing this check.  If the exclusion rules were
         // using closures that could be dynamically added to this class
         // then I'd put it below.
-        if ($this->weHavePassedTheMaxDepth($navItem)){
+        if ($this->weHavePassedTheMaxDepth($navItem)) {
             return;
         }
 
             // PageLists on the go at once.  This way we do a breadth first
             // pass and only have one PageList on the go at any one time.
             foreach ($pages as $childPage) {
-                if ($this->shouldInclude($childPage)) {
+                if ($this->shouldIncludePage($childPage)) {
                     $navItem->add($this->createNavItem($childPage));
                 }
             }
      * @param $page \Page
      * @return boolean
      */
-    protected function shouldInclude($page)
+    protected function shouldIncludePage($page)
     {
-        // would be nice if this was closure based... i.e.
-        // $navBuilder->excludePageIf(function($page) {$page->getCollectionAttributeValue('exclude_nav') == true});
-        // or perhaps
-        // $navBuilder->excludePageIf(Conditions::pageAttribute('exclude_nav').is(true));
-        //
-        $exclude = $page->getCollectionAttributeValue('exclude_nav') == true
-                   || $this->pagePathInExcludes($page);
+        $include = true;
+        // All include filters must be true to include a page.
+        foreach ($this->includePageConditions as $condition) {
+            if (is_callable($condition) && !call_user_func($condition, $page)) {
+                $include = false;
+                break;
+            }
+        }
+
+        if (!$include) {
+            return false;
+        }
+
+        $exclude = false;
+        foreach ($this->excludePageConditions as $condition) {
+            if (is_callable($condition) && call_user_func($condition, $page)) {
+                $exclude = true;
+                break;
+            }
+        }
+
+        if ($exclude || $this->pagePathInExcludes($page)) {
+            return false;
+        }
+
+        return true;
+    }
+
+    /**
+     * Called to check if the children of a particular page should be included.  The default
+     * implementation excludes children of pages whose 'exclude_children_from_nav' attribute
+     * is true.
+     *
+     * @param $page \Page
+     * @return boolean
+     */
+    protected function shouldIncludeChildren($page)
+    {
+        if (!is_callable($this->excludeChildrenCondition)) return true;
+
+        $exclude = call_user_func($this->excludeChildrenCondition, $page);
 
         return !$exclude;
     }
         return false;
     }
 
-    /**
-     * Adds a path path to the list of excludes.  E.g.
-     * <pre>
-     * $builder->excludeIfPathEquals('/members');
-     * </pre>
-     * @param $path
-     * @return void
-     */
-    public function excludeIfPathEquals($path) {
-       $this->excludedPaths[]= $path;
-    }
-
-    /**
-     * Called to check if the children of a particular page should be included.  The default
-     * implementation excludes children of pages whose 'exclude_children_from_nav' attribute
-     * is true.
-     *
-     * @param $page \Page
-     * @return boolean
-     */
-    protected function shouldIncludeChildren($page)
-    {
-        if (!is_callable($this->excludeChildrenCallback)) return true;
-
-        $exclude = call_user_func($this->excludeChildrenCallback, $page);
-
-        return !$exclude;
-    }
 
     /**
      * Factory method to create a concrete instance of NavItem.  You can create customised
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.