php - getting - laravel instalacion
Laravel Menu self recursion (4)
el modelo
class Menu extends Eloquent {
public static $table = ''menus'';
public function parent_menu()
{
return $this->belongs_to(''Menu'', ''parent_id'');
}
}
cómo lo tengo en el controlador:
$menus = Menu::with(''parent_menu'')->get();
¿Cómo lo renderizo en la vista?
foreach($menus as $m)
{
echo $m->parent_menu->title;
}
parece que hay un problema cuando la relación está dentro de una tabla, obtengo un error
`trying to get property of non object`
¿Existe alguna solucion para esto?
Esto puede ser de alguna ayuda. Heres cómo lo hice con categorías de productos / subcategorías
Modelo:
<?php
class Category extends Eloquent {
protected $table = ''product_category'';
public function subcat()
{
return $this->hasMany(''Category'', ''node_id'')->orderBy(''position'');
}
Consulta (puede usar condiciones cuando usa carga ansiosa)
$categories = Category::with([''subcat'' => function($query){
$query->with([''subcat'' => function($query){
$query->orderBy(''name'');
}])
}])->where(''node_id'', 0)->orderBy(''position'')->get([''id'', ''name'']);
foreach ($categories as $level1)
{
echo $level1->name;
foreach ($level1->subcat as $level2)
{
echo $level2->name;
foreach ($level2->subcat as $level3)
{
echo $level3->name;
}
}
}
He implementado una forma de obtener profundidad infinita en los menús de Laravel 4. No es exactamente lo que preguntas, pero la técnica debe ser fácilmente adaptable.
Para empezar, mi menú es solo una matriz (por ahora) que se asigna a la vista maestra y que se ve así.
$menu = array(
array(
''name'' => ''item1'',
''url'' => ''/''
),
array(
''name'' => ''item2'',
''url'' => ''/'',
''items'' => array(
array(
''name'' => ''subitem1'',
''url'' => ''/''
),
array(
''name'' => ''subitem2'',
''url'' => ''/''
)
)
)
);
También podría lograr fácilmente esta estructura usando un Modelo. Necesitará la función child_items
o algo así, ya que child_items
el menú de arriba hacia abajo, y no de abajo hacia arriba.
Ahora en mi plantilla de hoja maestro hago esto:
<ul>
@foreach ($menu as $item)
@include(''layouts._menuItem'', array(''item'' => $mainNavItem))
@endforeach
</ul>
Y luego en la plantilla layouts._menuItem
hago esto:
<?php
$items = array_key_exists(''items'', $item) ? $item[''items''] : false;
$name = array_key_exists(''name'', $item) ? $item[''name''] : '''';
$url = array_key_exists(''url'', $item) ? url($item[''url'']) : ''#'';
$active = array_key_exists(''url'', $item) ? Request::is($item[''url''].''/*'') : false;
?>
<li class="@if ($active) active @endif">
<a href="{{ $url }}">{{ $name }}</a>
@if ($items)
<ul>
@foreach ($items as $item)
@include(''layouts._menuItem'', array(''item'' => $item))
@endforeach
</ul>
@endif
</li>
Como puede ver, esta plantilla se llama recursivamente, pero con una variable de $item
diferente. Esto significa que puede ir tan profundo como desee en la estructura de su menú. (El bloque php está allí para preparar algunas variables para que pueda mantener el código de la plantilla real limpio y legible, técnicamente no es necesario).
Deshice el código de Twitter Bootstrap en los fragmentos de arriba para mantener las cosas simples (de hecho tengo títulos, menús desplegables, iconos, divisores, ... en mi plantilla / matriz), por lo que el código no se prueba. La versión completa está funcionando bien para mí, así que avíseme si cometí un error en alguna parte.
Espero que esto te ayude a ti (oa cualquier otra persona, porque esta es una pregunta bastante antigua) en el camino. Avíseme si necesita más punteros / ayuda, o si quiere mi código completo.
Feliz codificación!
Creo que la siguiente es la forma correcta de hacer recursividad en laravel.
Supongamos que tenemos una relación de niños, puede agregar esto a su clase de modelo:
public function getDescendants ( $parent= false ) {
$parent = $parent ?: $this;
$children = $parent->children()->get();
foreach ( $children as $child ) {
$child->setRelation(
''children'',
getDescendants( $child )
);
}
return $children;
}
Lo anterior obtendrá todos los registros de los niños de forma recursiva, y puede acceder a ellos de esta manera:
$d = Category::find(1)->getDescendants();
foreach ( $d as $child_level_1 ) {
foreach ( $child_level_1->children as $child_level_2 ) {
foreach ( $child_level_2->children as $child_level_3 ) {
// ...... this can go on for infinite levels
}
}
}
Aunque no se ha probado, lo siguiente puede ser útil para aplanar todas las relaciones recursivas en una colección de modelos ( consulte la documentación sobre cómo agregar nuevos métodos a las colecciones ):
// Add this to your model
public function newCollection ( array $models = array() ) {
return new CustomCollection( $models );
}
// Create a new file that extends the orginal collection
// and add the flattenRelation method
class CustomCollection extends Illuminate/Database/Eloquent/Collection {
// Flatten recursive model relations
public static function flattenRelation ( $relation ) {
$collection = $this;
// Loop through the collection models
foreach ( $collection as $model ) {
// If the relation exists
if ( isset($model->relations[$relation]) ) {
// Get it
$sub_collection = $model->relations[$relation];
// And merge it''s items with the original collection
$collection = $collection->merge(
$sub_collection->flatten($relation)
);
// Them remove it from the relations
unset( $model->relations[$relation] );
}
}
// Return the flattened collection
return $collection;
}
}
De esa forma puedes hacer lo siguiente:
// This will get the descenands and flatten them recursively
$d = Category::find(1)->getDescendants()->flattenRelation( ''children'' );
// This will give you a flat collection of all the descendants
foreach ( $d as $model ) {
}
Mi menú laravel con submenús ilimitados (elementos de menú de la base de datos)
public function CreateMenu( $parid, $menu, $level ) {
$output = array();
$action= Route::current()->getUri();
$uri_segments = explode(''/'', $action);
$count=count($uri_segments);
foreach( $menu as $item => $data ) {
if ($data->parent_id == $parid) {
$uri='''';
$output[ $data->id ] = $data;
for($i=0; $i<=$level; $i++) {
if($i < $count) {
$uri.="/".Request::segment($i+1);
}
if($uri == $data->link ) {
$output[ $data->id ]->activeClass = ''active'';
$output[ $data->id ]->inClass = ''in'';
}
else {
$output[ $data->id ]->activeClass = '''';
$output[ $data->id ]->inClass = '''';
}
$output[ $data->id ]->level = $level+2;
}
$output[ $data->id ]->submenu = self::CreateMenu( $data->id, $menu, $level+1 );
}
}
return $output;
}
En el BaseController o donde quieras, pon
$navitems=DB::table(''navigations'')->get();
$menu=BaseController::CreateMenu(0,$navitems,0);
return View::share($menu);
Después de eso, coloque el menú html en la macro.php
HTML::macro(''MakeNavigation'', function($data) {
foreach ($data as $key => $value) {
if($value->submenu) {
echo ''<li class="''.$value->activeClass.''">
<a href="''.$value->link.''" class="''.$value->activeClass.''">"''
.$value->name.'' <span class="fa arrow"></span>
</a>'';
echo "<ul class=''nav nav-".$value->level."-level ".$value->inClass." ''>";
HTML::MakeNavigation($value->submenu);
echo "</ul>";
}
else {
echo ''<li class="''.$value->activeClass.''">
<a href="''.$value->link.''" class="''.$value->activeClass.''">''
.$value->name.''
</a>'';
}
echo "</li>";
}});
Y en la vista (plantilla de hoja) simplemente llame al
{{ HTML::MakeNavigation($menu) }}