mlazuardy's avatar

Undefined variable

i want to show my tutorials page in localhost:8000/tutorials and make relationship between Tutorial Model and Category Model

Tutorial.php

<?php

namespace App;

use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Auth;
use TCG\Voyager\Facades\Voyager;
use TCG\Voyager\Traits\Translatable;
use App\Comment;
use TCG\Voyager\Models\Category;
class Tutorial extends Model
{
  use Translatable;

    protected $translatable = ['title', 'seo_title', 'excerpt', 'body', 'slug', 'meta_description', 'meta_keywords'];

    const PUBLISHED = 'PUBLISHED';

    protected $guarded = [];

    public function save(array $options = [])
    {
        // If no author has been assigned, assign the current user's id as the author of the post
        if (!$this->author_id && Auth::user()) {
            $this->author_id = Auth::user()->id;
        }

        parent::save();
    }

    public function authorId()
    {
        return $this->belongsTo(Voyager::modelClass('User'), 'author_id', 'id');
    }

    /**
     * Scope a query to only published scopes.
     *
     * @param \Illuminate\Database\Eloquent\Builder $query
     *
     * @return \Illuminate\Database\Eloquent\Builder
     */
    public function scopePublished(Builder $query)
    {
        return $query->where('status', '=', static::PUBLISHED);
    }

    /**
     * @return \Illuminate\Database\Eloquent\Relations\HasOne
     */
     public function category()
     {
         return $this->hasOne(Voyager::modelClass('Category'), 'id', 'category_id');
     }


    /**
     *   Method for returning specific thumbnail for post.
     */
    public function thumbnail($type)
    {
        // We take image from posts field
        $image = $this->attributes['image'];
        // We need to get extension type ( .jpeg , .png ...)
        $ext = pathinfo($image, PATHINFO_EXTENSION);
        // We remove extension from file name so we can append thumbnail type
        $name = rtrim($image, '.'.$ext);
        // We merge original name + type + extension
        return $name.'-'.$type.'.'.$ext;
    }
    public function comments()
    {
      return $this->hasMany(Comment::class);
    }



}

and the Category.php is

<?php

namespace TCG\Voyager\Models;

use Illuminate\Database\Eloquent\Model;
use TCG\Voyager\Facades\Voyager;
use TCG\Voyager\Traits\Translatable;
use TCG\Voyager\Models\Post;
use App\Tutorial;
class Category extends Model
{
    use Translatable;

    protected $translatable = ['slug', 'name'];

    protected $table = 'categories';

    protected $fillable = ['slug', 'name'];

    public function posts()
    {
        return $this->hasMany(Voyager::modelClass('Post'))
            ->published()
            ->orderBy('created_at', 'DESC');
    }
    //
    public function tutorials()
    {
      return $this->belongsTo(Tutorial::class);
    }
    //


    public function parentId()
    {
        return $this->belongsTo(self::class);
    }

    public function getRouteKeyName()
    {
      return 'slug';
    }
}

but its show whoops called ''undefined variable tutorial"

this is my index.blade.php to show the page


                @if ($tutorial->category->slug == 'desain-grafis')
                            @foreach($tutorials as $tutorial)

                                                <div class="col-md-3">
                                                            <a href="{{url('tutorial',$tutorial->slug)}}"><div class="card">
                                                                    <img class="card-image-top" src="/storage/{{$tutorial->image}}" alt"card image"></a>
                                              <a href="{{url('category',$tutorial->category->slug)}}" <span class="category">{{$tutorial->category->name}}</span></br>

                                                                        <h2 class="card-title">{{$tutorial->title}}</h2>
                                                                        <div class="commit-button-default">
                                                                                        <a href="{{url('tutorial',$tutorial->slug)}}" id="commit-button">See Detail</a>
                                                                        </div>


                                                                    </div>
                                                </div>

                              @endforeach
                                @endif
0 likes
13 replies
secondman's avatar

Are you passing a Tutorial model to your view?

Showing your Controller might help.

mlazuardy's avatar

this is the TutorialController

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use TCG\Voyager\Models\Category;
use App\Tutorial;
class TutorialController extends Controller
{
    //
    public function index()
    {
      $tutorials = Tutorial::paginate(12);

      return view('tutorial.index',compact('tutorials'));
    }

    public function show ($slug)
      {

      $tutorials = Tutorial::where('slug',$slug)->first();
      if(!$tutorials){
        abort(404);}
      return view('tutorial.show')->with('tutorial',$tutorials);
    }
}

and the CategoryController.php

<?php

namespace App\Http\Controllers;
use Illuminate\Support\Facades\DB;
use Illuminate\Http\Request;
use TCG\Voyager\Models\Post;
use TCG\Voyager\Models\Category;
use App\Tutorial;
class CategoryController extends Controller
{


    public function show($slug)
    {
        //

        $categories = Category::where('slug',$slug)->first();
        if(!$categories)
        {
          abort(404);
        }

        return view('categories.show')->with('categories',$categories);
      }

}
secondman's avatar

If you dd your $tutorials collection in the show method on TutorialController are you getting any results?

I'm a bit confused with your terminology for your variables, you're calling first on the model so you're only going to get a single row. I would suggest you use route model binding like so:

public function show (Tutorial $tutorial)
{
    return view('tutorial.show')->compact('tutorial');
}

As for your index view ... you haven't set the $tutorial variable in your controller, only $tutorials ....

Also I would suggest you eager load your relationships in the index so you don't make so many calls to the db:

public function index()
{
  $tutorials = Tutorial::with('category')->paginate(12);

  return view('tutorial.index', compact('tutorials'));
}
mlazuardy's avatar

how to to that? to sort the categories with slug of the category?

Snapey's avatar

Have you fixed your variable Undefined issue?

Now you have a new question?

Do you mean sort the tutorials with the slug of the category?

alabamustapha's avatar

@shawnmilke1 the condition: @if ($tutorial->category->slug == 'desain-grafis') should be within the: @foreach($tutorials as $tutorial) loop as you did not send a variable $tutorial to the view, you only send $tutorials.

You need to eager load your relationship for better performance.

mlazuardy's avatar

yes sir @Snapey how to do that, dont mention my code, i can format it to better logic with your answer. please help

mlazuardy's avatar

i update my Category and tutorials, change from Show method to Index Method and now show

Trying To get property of non object

here the code of Category.php

<?php

namespace TCG\Voyager\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Builder;
use TCG\Voyager\Facades\Voyager;
use TCG\Voyager\Traits\Translatable;
use TCG\Voyager\Models\Post;
use App\Tutorial;
class Category extends Model
{
    use Translatable;

    protected $translatable = ['slug', 'name'];

    protected $table = 'categories';

    protected $fillable = ['slug', 'name'];

    public function posts()
    {
        return $this->hasMany(Voyager::modelClass('Post'))
            ->published()
            ->orderBy('created_at', 'DESC');
    }
    //tutorials
    public function tutorials(){
      return $this->belongsTo(Tutorial::class,'id');
    }

    public function parentId()
    {
        return $this->belongsTo(self::class);
    }

    public function getRouteKeyName()
    {
      return 'slug';
    }
}

Tutorial.php

<?php

namespace App;

use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Auth;
use TCG\Voyager\Facades\Voyager;
use TCG\Voyager\Traits\Translatable;
use App\Comment;
use TCG\Voyager\Models\Category;
class Tutorial extends Model
{
  use Translatable;

    protected $translatable = ['title', 'seo_title', 'excerpt', 'body', 'slug', 'meta_description', 'meta_keywords'];

    const PUBLISHED = 'PUBLISHED';

    protected $guarded = [];

    public function save(array $options = [])
    {
        // If no author has been assigned, assign the current user's id as the author of the post
        if (!$this->author_id && Auth::user()) {
            $this->author_id = Auth::user()->id;
        }

        parent::save();
    }

    public function authorId()
    {
        return $this->belongsTo(Voyager::modelClass('User'), 'author_id', 'id');
    }

    /**
     * Scope a query to only published scopes.
     *
     * @param \Illuminate\Database\Eloquent\Builder $query
     *
     * @return \Illuminate\Database\Eloquent\Builder
     */
    public function scopePublished(Builder $query)
    {
        return $query->where('status', '=', static::PUBLISHED);
    }

    /**
     * @return \Illuminate\Database\Eloquent\Relations\HasOne
     */
     public function category()
     {
         return $this->hasOne(Voyager::modelClass('Category'), 'id', 'category_id');
     }


    /**
     *   Method for returning specific thumbnail for post.
     */
    public function thumbnail($type)
    {
        // We take image from posts field
        $image = $this->attributes['image'];
        // We need to get extension type ( .jpeg , .png ...)
        $ext = pathinfo($image, PATHINFO_EXTENSION);
        // We remove extension from file name so we can append thumbnail type
        $name = rtrim($image, '.'.$ext);
        // We merge original name + type + extension
        return $name.'-'.$type.'.'.$ext;
    }
    public function comments()
    {
      return $this->hasMany(Comment::class);
    }



}

if you need to see my Controller

CategoryController.php

<?php

namespace App\Http\Controllers;
use Illuminate\Support\Facades\DB;
use Illuminate\Http\Request;
use TCG\Voyager\Models\Post;
use TCG\Voyager\Models\Category;
use App\Tutorial;
class CategoryController extends Controller
{

        public function index()
        {

          $categories = Category::paginate(12);
          dd($categories);  
          return view('categories.index',compact('categories'));
        }

}

TutorialController.php

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use TCG\Voyager\Models\Category;
use App\Tutorial;
class TutorialController extends Controller
{
    //
    public function index()
    {
      $tutorials = Tutorial::paginate(12);

      return view('tutorial.index',compact('tutorials'));
    }

    public function show ($slug)
      {

      $tutorials = Tutorial::where('slug',$slug)->first();
      if(!$tutorials){
        abort(404);}
      return view('tutorial.show')->with('tutorial',$tutorials);
    }
}

view.

@foreach ($categories as $category)
        <div class="col-md-4">

              <a href=""><div class="card">
                  <img class="card-image-top" src="/storage/{{$category->post->image}}" alt"card image"></a>

                    <span class="category"></span>

                  </br>
                    <h2 class="card-title"></h2>
                    <div class="commit-button-default">
                            <a href="" id="commit-button">Read More</a>
                    </div>

                  </div>

        </div>



@endforeach

please fixed my code sir

secondman's avatar

I don't understand what your Voyager models are.

Are they Eloquent models? I could be wrong, but I don't think you can create relationships on non-Eloquent models, at least I've never seen it done.

You have models in TCG\Voyager\Models then you have other models in App, I can't make any sense of this code.

I would suggest you make your models in a single location App

If you need to pull in some other class do it there.

namespace App;

use TCG\Voyager\Models\Post;
use Illuminate\Database\Eloquent\Model;

class Category extends Model
{
    // new up your Post model if you need to
}

This is just a guess really ... the code doesn't make a whole lot of sense as is.

mlazuardy's avatar

that is the vendor model sir, should i make model again in App, and copying the entire of my vendor model?

Snapey's avatar

You have listed two controllers and three methods. Which one do you need fixing?

If your issue is that $categories is not defined, then it is because you do not pass it from the controller.

tutorialController


<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use TCG\Voyager\Models\Category;
use App\Tutorial;
class TutorialController extends Controller
{
    //
    public function index()
    {
      $tutorials = Tutorial::paginate(12);

      $categories = Category::all();

      return view('tutorial.index',compact('tutorials','categories'));
    }

    public function show ($slug)
      {

      $tutorial = Tutorial::where('slug',$slug)->firstOrFail();

      $categories = Category::all();

      return view('tutorial.show', compact('tutorial','categories');
    }
}

mlazuardy's avatar

im just fixing the categories and return the view to the same page

<?php

namespace App\Http\Controllers;
use Illuminate\Support\Facades\DB;
use Illuminate\Http\Request;
use TCG\Voyager\Models\Category;

class CategoryController extends Controller
{

        public function index(Category $category)
        {

          $posts = $category->posts()->paginate(12);
          return view('post.index',compact('posts'));
        }

}

it work , but the new problem is to show the Category name in the header of my page dynamically,

<div class="category-title">I want to this dynamically</div>
Snapey's avatar

ok, completely different problem then

reorganise;

<?php

namespace App\Http\Controllers;
use Illuminate\Support\Facades\DB;
use Illuminate\Http\Request;
use TCG\Voyager\Models\Category;

class CategoryController extends Controller
{

        public function index(Category $category)
        {

          $category->load('posts')->paginate(12);

          return view('post.index',compact('category'));
        }

}

view

<div class="category-title">{{ $category->title }}</div>

@foreach($category->posts as $post)

    // list out $post

@endforeach

Please or to participate in this conversation.