Bonjour,
J'ai suivi les tutos de grafikart et au lieu de faire comme lui pour les catégories, j'ai utilisé le treeBehavior actsAs afin de pouvoir gérer facilement les catégories et sous-catégories.
Voici les codes:
Dans le controller categories , ma fonction nav pour récupérer toutes les catégories
function nav(){
$categories = $this->Category->find('all');
return ($categories);
}
Puis, dans mon layout par défault
<?php echo $this->element('nav'); ?>
Dans View->Elements->nav.ctp
<ul>
<li><?php echo $this->Html->link('Accueil', array('controller' =>'posts', 'action' =>'index')); ?></li>
<?php $cat = $this->requestAction(array('controller' =>'categories', 'action'=>'nav', 'admin'=>false)); ?>
<li>
<a href="<?php echo $this->Html->url(array('controller'=>'posts','action'=>'category')); ?>" class="nav">
<?php echo $this->Tree->generate($cat); ?>
</a>
<?php debug($cat); ?>
</li>
</ul>
Dans le controller posts , pour afficher tous les posts lier à une catégorie quand on clique sur cette dernière
function category($category){
$cat = $this->Post->Category->find('first',array(
'conditions' => array('slug' => $category)
));
if(empty($cat))
throw new NotFoundException('Aucune catégorie ne correspond à ce nom');
$d'posts'] = $this->Paginate('Post',array('type'=>'post','online'=>1,'category_id' => $cat'Category']'id']));
$d'title'] = 'Tous les articles "'.$cat'Category']'name'].'"';
$this->set($d);
$this->render('index');
}
Dans le TreeHelper
<?php
/**
* Tree Helper.
*
* Used the generate nested representations of hierarchial data
*
* PHP versions 4 and 5
*
* Copyright (c) 2008, Andy Dawson
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @filesource
* @copyright Copyright (c) 2008, Andy Dawson
* @link www.ad7six.com
* @package cake-base
* @subpackage cake-base.app.views.helpers
* @since v 1.0
* @version $Revision: 1358 $
* @modifiedBy $LastChangedBy: skie $
* @lastModified $Date: 2009-10-15 05:49:11 -0500 (Thu, 15 Oct 2009) $
* @license http://www.opensource.org/licenses/mit-license.php The MIT License
*/
/**
* Tree helper
*
* Helper to generate tree representations of MPTT or recursively nested data
*/
class TreeHelper extends AppHelper {
/**
* name property
*
* @var string 'Tree'
* @access public
*/
public $name = 'Tree';
/**
* settings property
*
* @var array
* @access private
*/
private $__settings = array();
/**
* typeAttributes property
*
* @var array
* @access private
*/
private $__typeAttributes = array();
/**
* typeAttributesNext property
*
* @var array
* @access private
*/
private $__typeAttributesNext = array();
/**
* itemAttributes property
*
* @var array
* @access private
*/
private $__itemAttributes = array();
/**
* helpers variable
*
* @var array
* @access public
*/
public $helpers = array ('Html');
/**
* Tree generation method.
*
* Accepts the results of
* find('all', array('fields' => array('lft', 'rght', 'whatever'), 'order' => 'lft ASC'));
* children(); // if you have the tree behavior of course!
* or findAllThreaded(); and generates a tree structure of the data.
*
* Settings (2nd parameter):
* 'model' => name of the model (key) to look for in the data array. defaults to the first model for the current
* controller. If set to false 2d arrays will be allowed/expected.
* 'alias' => the array key to output for a simple ul (not used if element or callback is specified)
* 'type' => type of output defaults to ul
* 'itemType => type of item output default to li
* 'id' => id for top level 'type'
* 'class' => class for top level 'type'
* '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.
* 'left' => name of the 'lft' field if not lft. only applies to MPTT data
* 'right' => name of the 'rght' field if not lft. only applies to MPTT data
* 'depth' => used internally when running recursively, can be used to override the depth in either mode.
* '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
* style/float them.
* 'splitCount' => the number of "parallel" types. defaults to 3
*
* @param array $data data to loop on
* @param array $settings
* @return string html representation of the passed data
* @access public
*/
public function generate($data, $settings = array ()) {
$this->__settings = array_merge(array(
'model' => 'Category',
'alias' => 'name',
'type' => 'ul',
'itemType' => 'li',
'id' => false,
'class' => 'navsub',
'element' => false,
'callback' => false,
'autoPath' => false,
'left' => 'lft',
'right' => 'rght',
'depth' => 0,
'firstChild' => true,
'indent' => null,
'splitDepth' => false,
'splitCount' => 3,
), (array)$settings);
if ($this-> __settings'autoPath'] && !isset($this->__ settings'autoPath'][2])) {
$this->__settings'autoPath'][2] = 'active';
}
extract($this->__settings);
if ($indent === null && Configure::read('debug')) {
$indent = true;
}
$view =& ClassRegistry:: getObject('view');
if ($model === null) {
$model = Inflector::classify($view->params'models'][0]);
}
if (!$model) {
$model = '_NULL_';
}
$stack = array();
if ($depth == 0) {
if ($class) {
$this->addTypeAttribute('class', $class, null, 'previous');
}
if ($id) {
$this->addTypeAttribute('id', $id, null, 'previous');
}
}
$return = '';
if ($indent) {
$return = "\r\n";
}
$__addType = true;
foreach ($data as $i => $result) {
/* Allow 2d data arrays */
if ($model == '_NULL_') {
$_result = $result;
$result$model] = $_result;
}
/* BulletProof */
if (!isset($result$model]$left]) && !isset($result'children'])) {
$result'children'] = array();
}
/* Close open items as appropriate */
while ($stack && ($stack[count($stack)-1] < $result$model]$right])) {
array_pop($stack);
if ($indent) {
$whiteSpace = str_repeat("\t",count($stack));
$return .= "\r\n" . $whiteSpace . "\t";
}
if ($type) {
$return .= '</' . $type . '>';
}
if ($itemType) {
$return .= '</' . $itemType . '>';
}
}
/* Some useful vars */
$hasChildren = $firstChild = $lastChild = $hasVisibleChildren = false;
$numberOfDirectChildren = $numberOfTotalChildren = null;
if (isset($result'children'])) {
if ($result'children']) {
$hasChildren = $hasVisibleChildren = true;
$numberOfDirectChildren = count($result'children']);
}
$prevRow = prev($data);
if (!$prevRow) {
$firstChild = true;
}
next($data);
$nextRow = next($data);
if (!$nextRow) {
$lastChild = true;
}
prev($data);
} elseif (isset($result$model]$left])) {
if ($result$model]$left] != ($result$model]$right] - 1)) {
$hasChildren = true;
$numberOfTotalChildren = ($result$model]$right] - $result$model]$left] - 1) / 2;
if (isset($data$i + 1]) && $data$i + 1]$model]$right] < $result$model]$right]) {
$hasVisibleChildren = true;
}
}
if (!isset($data$i - 1]) || ($data$i - 1]$model]$left] == ($result$model]$left] - 1))) {
$firstChild = true;
}
if (!isset($data$i + 1]) || ($stack && $stack[count($stack) - 1] == ($result$model]$right] + 1))) {
$lastChild = true;
}
}
$elementData = array(
'data' => $result,
'depth' => $depth ? $depth : count($stack),
'hasChildren' => $hasChildren,
'numberOfDirectChildren' => $numberOfDirectChildren,
'numberOfTotalChildren' => $numberOfTotalChildren,
'firstChild' => $firstChild,
'lastChild' => $lastChild,
'hasVisibleChildren' => $hasVisibleChildren
);
$this-> __settings = array_merge($this->__ settings, $elementData);
/* Main Content */
if ($element) {
$content = $view->element($element, $elementData);
} elseif ($callback) {
list($content) = array_map($callback, array($elementData));
} else {
$content = $result$model]$alias];
}
if (!$content) {
continue;
}
$whiteSpace = str_repeat("\t", $depth);
if ($indent && strpos($content, "\r\n", 1)) {
$content = str_replace("\r\n", "\n" . $whiteSpace . "\t", $content);
}
/* Prefix */
if ($__addType) {
if ($indent) {
$return .= "\r\n" . $whiteSpace;
}
if ($type) {
$typeAttributes = $this->__attributes($type, array('data' => $elementData));
$return .= '<' . $type . $typeAttributes . '>';
}
}
if ($indent) {
$return .= "\r\n" . $whiteSpace . "\t";
}
if ($itemType) {
$itemAttributes = $this->__attributes($itemType, $elementData);
$return .= '<' . $itemType . $itemAttributes . '>';
}
$return .= $content;
/* Suffix */
$__addType = false;
if ($hasVisibleChildren) {
if ($numberOfDirectChildren) {
$settings'depth'] = $depth + 1;
$return .= $this->__suffix();
$return .= $this->generate($result'children'], $settings);
if ($itemType) {
$return .= '</' . $itemType . '>';
}
} elseif ($numberOfTotalChildren) {
$__addType = true;
$stack] = $result$model]$right];
}
} else {
if ($itemType) {
$return .= '</' . $itemType . '>';
}
$return .= $this->__suffix();
}
}
/* Cleanup */
while ($stack) {
array_pop($stack);
if ($indent) {
$whiteSpace = str_repeat("\t",count($stack));
$return .= "\r\n" . $whiteSpace . "\t";
}
if ($type) {
$return .= '</' . $type . '>';
}
if ($itemType) {
$return .= '</' . $itemType . '>';
}
}
if ($indent) {
$return .= "\r\n";
}
if ($type) {
$return .= '</' . $type . '>';
if ($indent) {
$return .= "\r\n";
}
}
return $return;
}
/**
* addItemAttribute function
*
* Called to modify the attributes of the next <item> to be processed
* Note that the content of a 'node' is processed before generating its wrapping <item> tag
*
* @param string $id
* @param string $key
* @param mixed $value
* @access public
* @return void
*/
public function addItemAttribute($id = '', $key = '', $value = null) {
if (!is_null($value)) {
$this->__itemAttributes$id]$key] = $value;
} elseif (!(isset($this-> __itemAttributes$id]) && in_array($key, $this->__ itemAttributes$id]))) {
$this->__itemAttributes$id]] = $key;
}
}
/**
* addTypeAttribute function
*
* Called to modify the attributes of the next <type> to be processed
* Note that the content of a 'node' is processed before generating its wrapping <type> tag (if appropriate)
* An 'interesting' case is that of a first child with children. To generate the output
* <ul> (1)
* <li>XYZ (3)
* <ul> (2)
* <li>ABC...
* ...
* </ul>
* ...
* The processing order is indicated by the numbers in brackets.
* attributes are allways applied to the next type (2) to be generated
* to set properties of the holding type - pass 'previous' for the 4th param
* i.e.
* // Hide children (2)
* $tree->addTypeAttribute('style', 'display', 'hidden');
* // give top level type (1) a class
* $tree->addTypeAttribute('class', 'hasHiddenGrandChildren', null, 'previous');
*
* @param string $id
* @param string $key
* @param mixed $value
* @access public
* @return void
*/
public function addTypeAttribute($id = '', $key = '', $value = null, $previousOrNext = 'next') {
$var = '__typeAttributes';
$firstChild = isset($this-> __settings'firstChild'])?$this->__ settings'firstChild']:true;
if ($previousOrNext == 'next' && $firstChild) {
$var = '__typeAttributesNext';
}
if (!is_null($value)) {
$this->{$var}$id]$key] = $value;
} elseif (!(isset($this->{$var}$id]) && in_array($key, $this->{$var}$id]))) {
$this->{$var}$id]] = $key;
}
}
/**
* supressChildren method
*
* @return void
* @access public
*/
public function supressChildren() {
}
/**
* suffix method
*
* Used to close and reopen a ul/ol to allow easier listings
*
* @access private
* @return void
*/
private function __suffix() {
static $__splitCount = 0;
static $__splitCounter = 0;
extract($this->__settings);
if ($splitDepth) {
if ($depth == $splitDepth -1) {
$total = $numberOfDirectChildren?$numberOfDirectChildren:$numberOfTotalChildren;
if ($total) {
$__splitCounter = 0;
$__splitCount = $total / $splitCount;
$rounded = (int)$__splitCount;
if ($rounded < $__splitCount) {
$__splitCount = $rounded + 1;
}
}
}
if ($depth == $splitDepth) {
$__splitCounter++;
if ($type && ($ __splitCounter % $__ splitCount) == 0) {
return '</' . $type . '><' . $type . '>';
}
}
}
return;
}
/**
* attributes function
*
* Logic to apply styles to tags.
*
* @param mixed $rType
* @param array $elementData
* @access private
* @return void
*/
private function __attributes($rType, $elementData = array(), $clear = true) {
extract($this->__settings);
if ($rType == $type) {
$attributes = $this->__typeAttributes;
if ($clear) {
$this-> __typeAttributes = $this->__ typeAttributesNext;
$this->__typeAttributesNext = array();
}
} else {
$attributes = $this->__itemAttributes;
$this->__itemAttributes = array();
if ($clear) {
$this->__itemAttributes = array();
}
}
if ($autoPath && $depth) {
if ($this-> __settings'data']$model]$left] < $autoPath[0] && $this->__ settings'data']$model]$right] > $autoPath[1]) {
$attributes'class']] = $autoPath[2];
} elseif (isset($autoPath[3]) && $this->__settings'data']$model]$left] == $autoPath[0]) {
$attributes'class']] = $autoPath[3];
}
}
if ($attributes) {
foreach ($attributes as $type => $values) {
foreach ($values as $key => $val) {
if (is_array($val)) {
$attributes$type]$key] = '';
foreach ($val as $vKey => $v) {
$attributes$type]$key]$vKey] .= $vKey . ':' . $v;
}
$attributes$type]$key] = implode(';', $attributes$type]$key]);
}
if (is_string($key)) {
$attributes$type]$key] = $key . ':' . $val . ';';
}
}
$attributes$type] = $type . '="' . implode(' ', $attributes$type]) . '"';
}
return ' ' . implode(' ', $attributes);
}
return '';
}
}
?>
J'ai fait un debug afin de voir le tableau qu'il génère
app\View\Elements\nav.ctp (line 14)
Array
(
[0] => Array
(
[Category] => Array
(
[id] => 2
[name] => Couture
[slug] => couture
[lft] => 1
[rght] => 2
[parent_id] => 0
[link] => Array
(
[controller] => posts
[action] => category
[slug] => couture
)
)
)
[1] => Array
(
[Category] => Array
(
[id] => 3
[name] => Cartonnage
[slug] => cartonnage
[lft] => 11
[rght] => 12
[parent_id] => 0
[link] => Array
(
[controller] => posts
[action] => category
[slug] => cartonnage
)
)
)
MON SOUCI est que je n'arrive pas à lier les catégories aux posts, quand je passe la souris sur un lien il me met posts/category, alors qu'il devrait m'ajouter le nom de la catégorie
Comment faire pour corriger tout ca? merci de votre aide
C'est bon tout est résolu
Dans le tuto, ils mettent ainsi
echo $html->link(
$data'Category']'libelle'],
array(
'controller' => 'categories',
'action' => 'view',
$data'Category']'id']
)
);
Comme avec le tuto de grafikart, on génère les slugs, il faut mettre ceci à la place
<?php echo $this->Html->link($data'Category']'name'], $data'Category']'link']); ?>
Avec le TreeHelper, il me génère bien le menu avec ul et li. Dans nav.ctp, j'ai ajouté le <a href> pour que la catégorie devienne un lien. et dans celui-ci, j'aurais voulu mettre $cat'Category']'link'], mais ca ne fonctionne pas car vu le debug, on s'aperçoit que c'est un tableau dans un tableau.
J'ai vu ce code là treeheleper
Et je constate qu'il utilise un extract ($data) mais ca je ne sais pas m'en servir.
Le souci, je m'aperçois que le lien qu'il génère actuellement est post/category, alors qu'il devrait me mettre category/(le nom de la catégorie)
Ainsi, quand je cliquerais sur la catégorie, ca affichera tous les posts liés à celui-ci
En regardant le code, je m'aperçois que le <a href> que j'ai mis dans nav.ctp n'est pas bon.
Donc, au final, je ne sais pas comment faire
J'ai vu le tuto arborescence
J'ai ma liste de catégories qui s'affiche correctement
J'ai suivi le tuto cakephp en 4 jours
Dans le TreeHelper version pour cakephp 2.0
A la ligne 141, j'ai modifié
$view =& ClassRegistry:: getObject('view');
A remplacer par:
$view =& $this->_View;
le souci que je rencontre, est que lorsqu'on clique sur une catégorie, qu'il affiche tous les posts liés à celle-ci.
Actuellement, le lien qu'il génère est le suivant:
http://localhost/blog/posts/index/posts/category/patchwork
Alors qu'il devrait être ainsi:
http://localhost/blog/categorie/patchwork
merci de votre aide