0

Ok, I am totally re-writing this question, now that I am a bit more familiar with larval.

Here is my situation: I have a guitar lessons site based on larval 5.2.36, where each lesson belongs to a category, and within a lesson are several exercises. An exercise table does not have a category id as it is linked to a lesson which has a category.

Goal What I am trying to figure out is how to pass the category of the currently displayed lesson or exercise to a menu sidebar view that displays the categories, so that the category of the lesson or exercise is highlighted. For this, I need to understand how to do such a task in laravel.

From what I gathered, this is often done via controllers. However, there is no menu controller, but rather a menu composer. It contains a function

class MenuComposer
{
    public function compose(View $view)
    {
        $minutes = 6 * 60;
        $value = Cache::remember('menu-categories', $minutes, function()       {
        return \App\Category::with('parent')->with('children')->get();
        });

        $view->with('categories', $value);
    }
}

Then in the menu blade file we have

@foreach ($categories as $category)
<?php $category = $category->present(); ?>

@if ($category->parent == null)
    <li><a href="{{ $category->url }}">{{ $category->title }}</a></li>

    @foreach ($category->children as $child)
        <?php $child = $child->present() ?>
        <li class="level1"><a href="{{ $child->url }}">{{ $child->title }}</a></li>

        <?php
            /*
            @foreach ($child->children as $grandChild)
                <?php $grandChild = $grandChild->present() ?>
                <li class="level2"><a href="{{ $grandChild->url }}">{{ $grandChild->title }}</a></li>
            @endforeach
            */
        ?>

        @endforeach

    @endif

@endforeach

So this is clear. I see that I can use the menu composer to pass additional data with a $view->with() call.

The question is how do I get the current category? For exercises and lessons, the routes don't have category data. They are of form

lesson/lessonid/lessontitle

or

exercise/exid/extitle

So I know I could do some sort of query of the model. But seems that wouldn't make sense, since I know there are other places in the process flow where the current cat is being passed. For instance, on an exercise page, the view is retrieving category as

$exercise->lesson->category->title

It is being passed this in exercise controller as

    public function index($id, $name = null)
{
    //$this->hit($id);
    $exercise = $this->apiController->get($id);
    $authorized = $this->isUserAuthorized();

    return view('exercise/index', [
            'exercise' => $exercise->present(),
            'authorized' => $authorized,
    ]);
}

Similarly, a lesson controller passes $lesson object to lesson view as

    public function index($id, $name = null)
{
    //$this->hit($id);
    $lesson = $this->apiController->get($id);
    $subscribed = $this->request->user() && $this->request->user()->subscribed('premium');

    return view('lesson/index', [
        'lesson' => $lesson->present(),
        'subscribed' => $subscribed,
    ]);
}

Based on above, seems I could modify the return statements in the lesson and exercise controller to pass the category to the menu view, but I don't see in the documentation how to do that, and I suspect the menu view is rendered before the lesson and exercise controller are called...

Also read about using service providers. middleware, etc, here: How to pass data to all views in Laravel 5?

But all these approaches seem overkill. I don't need every view to have the data. Seems to me, I need to do this somehow in the menu composer. But I don't know what method to use from the menu composer to retrieve the current lesson or exercise category. In the menu composer after debugging in phpstorm I see that the $view object for a lesson has $view->$data->$lesson->$entity.

So what I did was edited the menu composer to pass category to view:

    $d=$view->getdata();
    $s=array_key_exists ('lesson' , $d );
    if ($s ==1) $attr = collect($d)->get('lesson');
    $cat=$attr->cat();

This works since in the LessonPresenter I added function

    public function cat()
{
    $cat = $this->entity->category['attributes']['title'];
    return $cat;
}

This works, but I feel like it is a hack. And I will have to do this for the Exercise Presenter as well. Being new to larval I suspect there has to be a more elegant way to do this. So can someone please explain how this should be done?

thanks,

Brian

Community
  • 1
  • 1
Brian
  • 125
  • 2
  • 15
  • I think you can do that in javascript with ajax. The same logic as in php applies. Can you retrieve something from an html page in php without an ajax request or sending a form? – Indra May 12 '17 at 12:34

2 Answers2

0

You can use Facades of Laravel directly in blade templates.

Just use {! !} syntax to try and echo it. e.g: {!! Route::current() !!}

There are also similar functions of Route facade you can use.

Then, you can check your category with @if() ... @endif blocks and add something like class name within it.

Note: Don't put lots of logic in your blade files. Do it in your controller file (even in your other service classes) and pass simplest variables (e.g $isCurrentCategory) as an array to your template files using View::make() function's 2nd parameter.

Koray Küpe
  • 716
  • 6
  • 24
  • I see that from the route I can obtain ID of the item being displayed. I was hoping there would be some object that has all parameters of the content. I was used to how things are in Joomla where I always had a $this object with everything I could want to know about the item. In larval, I am just not sure how to go about this. For my site, an exercise is attached to a lesson, which has a category. So getting exercise category would amount to a JOIN query. I just don't know whether this is what I have to do in larvel, or if there is some object that already contains the data I am looking for... – Brian May 12 '17 at 14:14
  • _"...all parameters of the content..."_ You must pass the content object to your view in your controller. It doesn't make it automatically. You need to get your data from model first in your controller and pass it to the blade template. This is for basic example. Actually, using model queries in controller is a bad practice. You can create repositories but it is a more advanced subject. Ignore it for now. Refer to: https://laravel.com/docs/5.4/blade#displaying-data – Koray Küpe May 12 '17 at 14:19
  • Ok, I guess I just need to get used to the larval way of thinking. I just realized that in the blade file I can use $exercise->lesson->category->title which I suppose amounts to getting the data from the model. I just wasn't sure if laravel had its own object that has the data already, or if I have to use application specific approach. Thanks! – Brian May 12 '17 at 14:27
0

Maybe this can help you

<a href="#" class="{{ (\Request::route()->getName() == 'routename') ? 'active' : '' }}">

You can also get the route prefix for example, you can check this out here:

Laravel API Docs Routing

Robert Fridzema
  • 517
  • 3
  • 18