Leandro Dimitrio
Leandro Dimitrio

Reputation: 112

Get child items recursively with PHP

I have a table in MySQL that holds Menu Items, and each has a parent, that can be either 0 (Top Menu) or the ID of another Item.

I'm working on a controller within CodeIgniter that was started by another programmer, and here's the brilliant way he found to sweep through the items of each item, recursively.

// I know there's a better way to do this, but as time is short we have to run
$data['aplicacoes_list'] = '';
$aplicacoes = $this->aplicacoes_model->get_aplicacoes_no_parent();
foreach($aplicacoes as $apl){                
    $data['aplicacoes_list'] .= '<li class="dd-item" data-id="3">
        <div class="dd-handle">'.$apl['nome'].'
            <div class="pull-right"><a href="#" id="'.$apl['nome'].'_'.$apl['id'].'" data-toggle="modal" data-target="#ModalEditarAplicacao" class="dd-nodrag editarAplicacao btn-xs btn-primary"><i class="fa fa-edit"></i><span class="hidden-block hidden-xs hidden-sm"> Editar</span></a>&nbsp;<a href="#" id="'.$apl['nome'].'_'.$apl['id'].'" data-toggle="modal" data-target="#ModalAdicionarSubaplicacao" class="dd-nodrag adicionarSubAplicacao btn-xs btn-success"><i class="fa fa-plus"></i> <span class="hidden-block hidden-xs hidden-sm">Adicionar subcategoria</span></a>&nbsp;<a href="#" data-toggle="modal" data-target="#ModalRemoverAplicacao" id="'.$apl['id'].'" class="dd-nodrag aplicacaoRemover btn-xs btn-danger"><i class="fa fa-trash-o"></i><span class="hidden-block hidden-xs hidden-sm"> Remover</span></a></div>
        </div>
    </li>';
    $sub_aplicacoes = $this->aplicacoes_model->get_aplicacoes_by_parent_id($apl['id']);
    foreach($sub_aplicacoes as $sub_apl){
        $data['aplicacoes_list'] .= '<ol class="dd-list">
        <li class="dd-item" data-id="4">
            <div class="dd-handle">'.$sub_apl['nome'].'
                <div class="pull-right"><a href="#" id="'.$sub_apl['nome'].'_'.$sub_apl['id'].'" data-toggle="modal" data-target="#ModalEditarAplicacao" class="dd-nodrag editarAplicacao btn-xs btn-primary"><i class="fa fa-edit"></i><span class="hidden-block hidden-xs hidden-sm"> Editar</span></a>&nbsp;<a href="#" id="'.$sub_apl['nome'].'_'.$sub_apl['id'].'" data-toggle="modal" data-target="#ModalAdicionarSubaplicacao" class="dd-nodrag adicionarSubAplicacao btn-xs btn-success"><i class="fa fa-plus"></i> <span class="hidden-block hidden-xs hidden-sm">Adicionar subcategoria</span></a>&nbsp;<a href="#" data-toggle="modal" data-target="#ModalRemoverAplicacao" id="'.$sub_apl['id'].'" class="dd-nodrag aplicacaoRemover btn-xs btn-danger"><i class="fa fa-trash-o"></i><span class="hidden-block hidden-xs hidden-sm"> Remover</span></a></div>
            </div>
        </li>';                        
        $sub_aplicacoes2 = $this->aplicacoes_model->get_aplicacoes_by_parent_id($sub_apl['id']);
        foreach($sub_aplicacoes2 as $sub_apl2){    
            $data['aplicacoes_list'] .= '<ol class="dd-list">
            <li class="dd-item" data-id="4">
                <div class="dd-handle">'.$sub_apl2['nome'].'
                    <div class="pull-right"><a href="#" id="'.$sub_apl2['nome'].'_'.$sub_apl2['id'].'" data-toggle="modal" data-target="#ModalEditarAplicacao" class="dd-nodrag editarAplicacao btn-xs btn-primary"><i class="fa fa-edit"></i><span class="hidden-block hidden-xs hidden-sm"> Editar</span></a>&nbsp;<a href="#" id="'.$sub_apl2['nome'].'_'.$sub_apl2['id'].'" data-toggle="modal" data-target="#ModalAdicionarSubaplicacao" class="dd-nodrag adicionarSubAplicacao btn-xs btn-success"><i class="fa fa-plus"></i> <span class="hidden-block hidden-xs hidden-sm">Adicionar subcategoria</span></a>&nbsp;<a href="#" data-toggle="modal" data-target="#ModalRemoverAplicacao" id="'.$sub_apl2['id'].'" class="dd-nodrag aplicacaoRemover btn-xs btn-danger"><i class="fa fa-trash-o"></i><span class="hidden-block hidden-xs hidden-sm"> Remover</span></a></div>
                </div>
            </li>';
        }
    }
}

So, as you can see, the list goes on until $sub_aplicacoes7, which is just moronic.

Can you guys think of a better way to accomplish this?

Here's a screenshot of the database, as it is.

Upvotes: 1

Views: 109

Answers (2)

Oleg Dubas
Oleg Dubas

Reputation: 2348

Here's a recursive method for you:

private function recursive_aplicacoes( $parent = 0 )
{
    $sub_aplicacoes = $this->aplicacoes_model->get_aplicacoes_by_parent_id($parent);

    if(!count($sub_aplicacoes)) return '';

    $s = '<ol class="dd-list">';
    foreach($sub_aplicacoes as $sub_apl)
    {
        $s .= '<li class="dd-item" data-id="4">
                    <div class="dd-handle">'.$sub_apl['nome'].'
                        <div class="pull-right"><a href="#" id="'.$sub_apl['nome'].'_'.$sub_apl['id'].'" data-toggle="modal" data-target="#ModalEditarAplicacao" class="dd-nodrag editarAplicacao btn-xs btn-primary"><i class="fa fa-edit"></i><span class="hidden-block hidden-xs hidden-sm"> Editar</span></a>&nbsp;<a href="#" id="'.$sub_apl['nome'].'_'.$sub_apl['id'].'" data-toggle="modal" data-target="#ModalAdicionarSubaplicacao" class="dd-nodrag adicionarSubAplicacao btn-xs btn-success"><i class="fa fa-plus"></i> <span class="hidden-block hidden-xs hidden-sm">Adicionar subcategoria</span></a>&nbsp;<a href="#" data-toggle="modal" data-target="#ModalRemoverAplicacao" id="'.$sub_apl['id'].'" class="dd-nodrag aplicacaoRemover btn-xs btn-danger"><i class="fa fa-trash-o"></i><span class="hidden-block hidden-xs hidden-sm"> Remover</span></a></div>
                    </div>
                </li>';
        $s .= $this->recursive_aplicacoes($sub_apl['id']);

    }
    $s .= '</ol>';
    return $s;
}

Put it in same class.
Here's how to use:

$data['aplicacoes_list'] = $this->recursive_aplicacoes();

Should work :)

Upvotes: 2

xsist10
xsist10

Reputation: 3051

You could move the code for generating a submenu into it's own function and use recursion. While this will solve your problem may I recommend that, once you've built the menu for a user that you cache it until s/he logs out as your menu system can quickly become quite complex and slow to load the more embedded menus you add (you end up with an recursive N + 1 problem).

$data['aplicacoes_list'] = '';
$aplicacoes = $this->aplicacoes_model->get_aplicacoes_no_parent();

foreach($aplicacoes as $apl){                
    $data['aplicacoes_list'] .= '<li class="dd-item" data-id="3">
        <div class="dd-handle">'.$apl['nome'].'
            <div class="pull-right"><a href="#" id="'.$apl['nome'].'_'.$apl['id'].'" data-toggle="modal" data-target="#ModalEditarAplicacao" class="dd-nodrag editarAplicacao btn-xs btn-primary"><i class="fa fa-edit"></i><span class="hidden-block hidden-xs hidden-sm"> Editar</span></a>&nbsp;<a href="#" id="'.$apl['nome'].'_'.$apl['id'].'" data-toggle="modal" data-target="#ModalAdicionarSubaplicacao" class="dd-nodrag adicionarSubAplicacao btn-xs btn-success"><i class="fa fa-plus"></i> <span class="hidden-block hidden-xs hidden-sm">Adicionar subcategoria</span></a>&nbsp;<a href="#" data-toggle="modal" data-target="#ModalRemoverAplicacao" id="'.$apl['id'].'" class="dd-nodrag aplicacaoRemover btn-xs btn-danger"><i class="fa fa-trash-o"></i><span class="hidden-block hidden-xs hidden-sm"> Remover</span></a></div>
        </div>
    </li>' . build_submenu($this->aplicacoes_model, $apl['id']);
}


function build_submenu($model, $id) {
    $aplicacoes = $model->get_aplicacoes_by_parent_id($id);
    if (empty($aplicacoes)) {
        return '';
    }

    $submenu = '';
    foreach($aplicacoes as $sub){
        $submenu .= '<ol class="dd-list">
        <li class="dd-item" data-id="4">
            <div class="dd-handle">'.$sub['nome'].'
                <div class="pull-right"><a href="#" id="'.$sub['nome'].'_'.$sub['id'].'" data-toggle="modal" data-target="#ModalEditarAplicacao" class="dd-nodrag editarAplicacao btn-xs btn-primary"><i class="fa fa-edit"></i><span class="hidden-block hidden-xs hidden-sm"> Editar</span></a>&nbsp;<a href="#" id="'.$sub['nome'].'_'.$sub['id'].'" data-toggle="modal" data-target="#ModalAdicionarSubaplicacao" class="dd-nodrag adicionarSubAplicacao btn-xs btn-success"><i class="fa fa-plus"></i> <span class="hidden-block hidden-xs hidden-sm">Adicionar subcategoria</span></a>&nbsp;<a href="#" data-toggle="modal" data-target="#ModalRemoverAplicacao" id="'.$sub['id'].'" class="dd-nodrag aplicacaoRemover btn-xs btn-danger"><i class="fa fa-trash-o"></i><span class="hidden-block hidden-xs hidden-sm"> Remover</span></a></div>
            </div>
        </li>' . build_submenu($model, $sub['id']);
    }
    return $submenu;
}

You may need to fiddle with this to get the correct HTML tags/CSS that you need.

Upvotes: 0

Related Questions