ソースを参照

Improve auto class.

mscherer 7 年 前
コミット
fcd2e9e33b

+ 56 - 6
docs/Helper/Tree.md

@@ -5,9 +5,12 @@ A CakePHP helper to handle tree structures.
 By default, it uses the core TreeBehavior and MPTT (Modified Preorder Tree Traversal).
 But it sure can work with any tree like input as nested object or array structure.
 
-### Usage
+It can work with both arrays and Entity objects. The latter should be preferred as you can
+then use all properties and getters on that object.
 
-#### Basic usage
+## Usage
+
+### Basic usage
 Include helper in your AppView class as
 ```php
 $this->addHelper('Tools.Tree', [
@@ -20,7 +23,7 @@ Then you can use it in your templates as
 echo $this->Tree->generate($articles);
 ```
 
-#### Templated usage
+### Templated usage
 By default, just outputting the display name is usually not enough.
 You want to create some `Template/Element/tree_element.ctp` element instead:
 
@@ -35,20 +38,25 @@ That template can then contain all normal template additions, including full hel
 /**
  * @var \App\View\AppView $this
  * @var \App\Model\Entity\Article|\Cake\Collection\CollectionInterface $data
+ * @var bool $activePathElement
  */
 
 if (!$data->visible) { // You can do anything here depending on the record content
 	return;
 }
+$label = $data->title;
+if ($activePathElement) {
+	$label .= ' (active)';
+}
 ?>
 <li>
-<?php echo $this->Html->link($data->title, ['action' => 'view', $data->id]); ?>
+<?php echo $this->Html->link($label, ['action' => 'view', $data->id]); ?>
 </li>
 ```
 
 So the current entity object is available as `$data` variable inside this snippet.
 
-### Available element/callback data
+#### Available element data
 
 - $data : object|object[]|array
 - $parent : object|array|null
@@ -64,6 +72,48 @@ So the current entity object is available as `$data` variable inside this snippe
 
 plus all config values. 
 
-### Outview
+### Callback usage
+
+Here the same keys are available on the first argument (`$data` array). So the above `$data` would actually be
+`$data['data']` and usually be the entity. 
+If you are passing entities, it helps to inline annotate in this case:
+```php
+	$closure = function(array $data) {
+		/** @var \Cake\ORM\Entity $entity */
+		$entity = $data['data'];
+
+		return h($entity->name) . ($data['activePathElement'] ? ' (active)' : '');
+	};
+```
+
+### Active path
+When using the TreeHelper for navigation structures, you would usually want to set the active path as class elements ("active") 
+on the `<li>` elements.
+You can do that by passing in the current path.
+```php
+// Your controller fetches the navigation tree
+$tree = $this->Table->find('threaded')->toArray();
+
+// The current active element in the tree (/view/6)
+$id = 6;
+		
+// We need to get the current path for this element
+$nodes = $this->Table->find('path', ['for' => $id]);
+$path = $nodes->extract('id')->toArray();
+
+// In your view
+$options = [
+	'autoPath' => [$current->lft, $current->rght], 
+	'treePath' => $path, 
+	'element' => 'tree', // src/Template/Element/tree.ctp
+];
+echo $this->Tree->generate($tree, $options);
+```
+The `autoPath` setting passed using `[lft, rght]` of your current element will auto-add "active" into your elements.
+You can also just pass the current entity (`'autoPath' => $current`) and it will extract lft and rght properties based on the config.
+
+The `treePath` is optional and needed for additional things like hiding unrelated siblings etc.
+
+## Outview
 
 You can read some more tutorial like details in [my blog post](http://www.dereuromark.de/2013/02/17/cakephp-and-tree-structures/).

+ 13 - 4
src/View/Helper/TreeHelper.php

@@ -38,6 +38,7 @@ class TreeHelper extends Helper {
 		'element' => false,
 		'callback' => false,
 		'autoPath' => false,
+		'autoPathClass' => 'active',
 		'hideUnrelated' => false,
 		'treePath' => [],
 		'left' => 'lft',
@@ -100,12 +101,13 @@ class TreeHelper extends Helper {
 	 *    'element' => path to an element to render to get node contents.
 	 *    'callback' => callback to use to get node contents. e.g. array(&$anObject, 'methodName') or 'floatingMethod'
 	 *    'autoPath' => array($left, $right [$classToAdd = 'active']) if set any item in the path will have the class $classToAdd added. MPTT only.
-	 *  'hideUnrelated' => if unrelated (not children, not siblings) should be hidden, needs 'treePath', true/false or array/string for callback
-	 *  'treePath' => treePath to insert into callback/element
+	 *      You can also just pass the current entity and it will extract lft and rght properties based on the config.
+	 *    'hideUnrelated' => if unrelated (not children, not siblings) should be hidden, needs 'treePath', true/false or array/string for callback
+	 *    'treePath' => treePath to insert into callback/element
 	 *    'left' => name of the 'lft' field if not lft. only applies to MPTT data
 	 *    'right' => name of the 'rght' field if not rght. only applies to MPTT data
 	 *    'depth' => used internally when running recursively, can be used to override the depth in either mode.
-	 *  'maxDepth' => used to control the depth upto which to generate tree
+	 *    'maxDepth' => used to control the depth upto which to generate tree
 	 *    'firstChild' => used internally when running recursively.
 	 *    'splitDepth' => if multiple "parallel" types are required, instead of one big type, nominate the depth to do so here
 	 *        example: useful if you have 30 items to display, and you'd prefer they appeared in the source as 3 lists of 10 to be able to
@@ -140,8 +142,15 @@ class TreeHelper extends Helper {
 		}
 
 		$this->_config = $config + $this->_defaultConfig;
+		if ($this->_config['autoPath'] && is_object($this->_config['autoPath'])) {
+			$autoPathEntity = $this->_config['autoPath'];
+			$propertyLeft = $this->_config['left'];
+			$propertyRight = $this->_config['right'];
+			$this->_config['autoPath'] = [$autoPathEntity->$propertyLeft, $autoPathEntity->$propertyRight];
+		}
+
 		if ($this->_config['autoPath'] && !isset($this->_config['autoPath'][2])) {
-			$this->_config['autoPath'][2] = 'active';
+			$this->_config['autoPath'][2] = $this->_config['autoPathClass'];
 		}
 		extract($this->_config);
 		if ($indent === null && Configure::read('debug')) {

+ 46 - 6
tests/TestCase/View/Helper/TreeHelperTest.php

@@ -136,7 +136,6 @@ TEXT;
 		$tree = $this->Table->find('all', ['order' => ['lft' => 'ASC']])->toArray();
 
 		$output = $this->Tree->generate($tree);
-		//debug($output); return;
 		$expected = <<<TEXT
 
 <ul>
@@ -328,7 +327,6 @@ TEXT;
 		$this->assertTextEquals($expected, $output);
 
 		$output = $this->Tree->generate($tree, ['autoPath' => [8, 9]]); // Two-SubA-1-1
-		//debug($output);
 		$expected = <<<TEXT
 
 <ul>
@@ -363,6 +361,49 @@ TEXT;
 	}
 
 	/**
+	 * @return void
+	 */
+	public function testGenerateWithAutoPathAsEntity() {
+		$tree = $this->Table->find('threaded')->toArray();
+		$entity = new Entity();
+		$entity->lft = 7;
+		$entity->rght = 10;
+
+		$output = $this->Tree->generate($tree, ['autoPath' => $entity]);
+		$expected = <<<TEXT
+
+<ul>
+	<li>One
+	<ul>
+		<li>One-SubA</li>
+	</ul>
+	</li>
+	<li class="active">Two
+	<ul>
+		<li class="active">Two-SubA
+		<ul>
+			<li class="active">Two-SubA-1
+			<ul>
+				<li>Two-SubA-1-1</li>
+			</ul>
+			</li>
+		</ul>
+		</li>
+	</ul>
+	</li>
+	<li>Three</li>
+	<li>Four
+	<ul>
+		<li>Four-SubA</li>
+	</ul>
+	</li>
+</ul>
+
+TEXT;
+		$this->assertTextEquals($expected, $output);
+	}
+
+	/**
 	 * - One
 	 * -- One-SubA
 	 * - Two
@@ -483,7 +524,7 @@ TEXT;
 	 * @param array $data
 	 * @return string|null
 	 */
-	public function _myCallback($data) {
+	public function _myCallback(array $data) {
 		/** @var \Cake\ORM\Entity $entity */
 		$entity = $data['data'];
 		if (!empty($entity['hide'])) {
@@ -496,7 +537,7 @@ TEXT;
 	 * @param array $data
 	 * @return string|null
 	 */
-	public function _myCallbackSiblings($data) {
+	public function _myCallbackSiblings(array $data) {
 		/** @var \Cake\ORM\Entity $entity */
 		$entity = $data['data'];
 
@@ -576,7 +617,6 @@ TEXT;
 </ul>
 
 TEXT;
-		debug($output);
 		$output = str_replace(["\t", "\r", "\n"], '', $output);
 		$expected = str_replace(["\t", "\r", "\n"], '', $expected);
 		$this->assertTextEquals($expected, $output);
@@ -586,7 +626,7 @@ TEXT;
 	 * @param array $data
 	 * @return string|null
 	 */
-	public function _myCallbackEntity($data) {
+	public function _myCallbackEntity(array $data) {
 		/** @var \Cake\ORM\Entity $entity */
 		$entity = $data['data'];