I'm facing against this problem since yesterday.
I have a db table called resources have a foreign key linked to another table called category.
I'm trying to retrieve the description field in my blade view, but I get this error:
Trying to get property 'description' of non-object.
My blade view:
#extends('templates.header')
#section('section')
<div class="p-10 grid grid-cols-1 sm:grid-cols-1 md:grid-cols-3 lg:grid-cols-3 xl:grid-cols-3 gap-5">
#foreach($resources as $resource)
<div class="max-w-sm rounded overflow-hidden shadow-lg">
{{-- <img class="w-full" src="#" alt="Mountain"> --}}
<div class="px-6 py-4">
<div class="font-bold text-xl mb-2">
{{ $resource->name }}
</div>
<p class="text-gray-700 text-base">
{{ $resource->description }}
</p>
</div>
<div class="px-6 pt-4 pb-2">
<span class="inline-block bg-gray-200 rounded-full px-3 py-1 text-sm font-semibold text-gray-700 mr-2 mb-2">{{ $resource->categor->description }}</span>
<span class="inline-block bg-gray-200 rounded-full px-3 py-1 text-sm font-semibold text-gray-700 mr-2 mb-2">{{ $resource->status }}</span>
<span class="inline-block bg-gray-200 rounded-full px-3 py-1 text-sm font-semibold text-gray-700 mr-2 mb-2">{{ $resource->centerId }}</span>
<button type="submit" class="inline-flex justify-center py-2 px-4 border border-transparent shadow-sm text-sm font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500">
Prenota
</button>
</div>
</div>
#endforeach
</div>
#endsection
My Resource Model:
namespace App\Models;
use App\Models\Category;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Resource extends Model
{
use HasFactory;
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
'name',
'description',
'category',
'inventoryN',
'status',
'centerId',
];
/**
* The attributes that should be hidden for arrays.
*
* #var array
*/
protected $hidden = [
];
/**
* The attributes that should be cast to native types.
*
* #var array
*/
protected $casts = [
];
public function category()
{
return $this->hasOne(Category::class, 'id', 'category');
}
}
My Category Model:
namespace App\Models;
use App\Models\Resource;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Category extends Model
{
use HasFactory;
protected $table = 'categories';
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
'description',
];
/**
* The attributes that should be hidden for arrays.
*
* #var array
*/
protected $hidden = [
];
/**
* The attributes that should be cast to native types.
*
* #var array
*/
protected $casts = [
];
public function resource()
{
return $this->belongsTo(Resource::class, 'category');
}
}
And lastly my ResourceController:
namespace App\Http\Controllers;
use App\Models\Category;
use App\Models\Resource;
use Illuminate\Http\Request;
class ResourceController extends Controller
{
public function index()
{
$resources = Resource::with('category')->get();
return view('resources', compact('resources'));
}
}
This is a dd of "$resources":
dd of $resources
You have a few mistakes here.
The first is in the Blade. You need to fix a typo
$resource->categor->description
// should be
$resource->category->description
Then I recommend changing your schema by changing your resources column from category to category_id.
This will help Laravel auto populate the values in the below snippets.
Next, you need to fix your relationships.
In the Resources model, you need
public function category()
{
return $this->hasOne(Category::class);
}
I have removed the second and third parameters, these are autofilled by Laravel; and since you are using Laravel's naming schemes, you don't need it.
What you had previously was stating that the table was the singular variant of category, which it wasn't.
Then you need to change your Category model to
public function resource()
{
return $this->belongsTo(Resource::class);
}
The reason this was failing is because Laravel was returning null, because the column names weren't quite correct.
It's easier to just have a more standard naming structure in your Database as it helps other developers, and makes your life easier when using Laravel.
There is a typo in your category viewing. I think that's the problem.
{{ $resource->categor->description }}
vs.
{{ $resource->category->description }}
Related
I'm creating a clone for a website where parents can create a list of things they need for their newborn baby so other people can buy it for them as a gift.
At this moment I've managed to insert data into my table and to link that row of data to the user id (so user who is logged in and completed the form).
I've managed to show all the lists from all the user id's but when I go to the dashboard of the authenticated user, I only want to show the lists who is linked to his user_id.
I can't get it working but I'm sure I have to use hasMany() and belongsTo().
This is my code:
My migration:
public function up()
{
Schema::create('users', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->string('email')->unique;
$table->binary('password');
$table->enum('role', ['user','admin'])->default('user');
$table->timestamp('created_at');
$table->timestamp('updated_at');
});
Schema::create('lists', function (Blueprint $table)
{
$table->increments('id');
$table->foreignId('user_id')->nullable()->constrained()->onDelete('cascade');
$table->string('baby');
$table->string('vader');
$table->string('moeder');
$table->integer('telefoonnummer');
$table->string('email');
$table->string('adres');
$table->integer('huisnummer');
$table->string('toevoeging')->nullable();
$table->string('stad');
$table->integer('postcode');
$table->string('land');
});
}
My User model:
class User extends Authenticatable
{
use HasApiTokens, HasFactory, Notifiable;
/**
* The attributes that are mass assignable.
*
* #var array<int, string>
*/
protected $fillable = [
'name',
'email',
'password',
];
/**
* The attributes that should be hidden for serialization.
*
* #var array<int, string>
*/
protected $hidden = [
'password',
'remember_token',
];
/**
* The attributes that should be cast.
*
* #var array<string, string>
*/
protected $casts = [
'email_verified_at' => 'datetime',
];
public function birthLists()
{
return $this->hasMany(Birthlist::class, 'user_id');
}
}
My Birthlist model:
class Birthlist extends Model
{
use HasFactory;
protected $table = 'lists';
protected $primaryKey = 'id';
protected $fillable =
[
'user_id',
'baby',
'vader',
'moeder',
'telefoonnummer',
'email',
'adres',
'huisnummer',
'toevoeging',
'stad',
'postcode',
'land'
];
public $timestamps = false;
public function user()
{
return $this->belongsTo(User::class, 'user_id');
}
}
My controller
<?php
namespace App\Http\Controllers;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use App\Providers\RouteServiceProvider;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use App\Models\User;
use App\Models\Birthlist;
class DashController extends Controller
{
public function dashboard($id)
{
$userId = Auth::id();
$lists = Birthlist::where('user_id')->first();
return view('dashboard', [
'lists' => $lists,
]);
}
}
My view
<body class="bg-red-100 w-screen h-screen pb">
<main class="">
<div class="text-center p-8 bg-green-100">
<p class="">welkom</p>
<h2 class="text-3xl font-bold">{{ Auth::user()->name }}</h2>
</div>
<section class="bg-red-100">
<span class="p-4"><p class="text-center text-xl font-semibold">Mijn lijsten</p></span>
#foreach ($lists->birthLists as $list)
<div class="bg-red-200 p-8 bg-gradient-to-b from-green-300 to-fuchsia-400 drop-shadow-xl text-white md:w-5/12 xl:w-3/12">
<div class="text-3xl font-bold">
{{ $list->baby }}
</div>
<div class="flex flex-row justify-between">
{{ $list->vader }} & {{ $list->moeder }}
</div>
</div>
#endforeach
</section>
</main>
#include('partials.footer')
</body>
In User model :
public function birthLists()
{
return $this->hasMany(Birthlist::class);
}
and in view :
<body class="bg-red-100 w-screen h-screen pb">
<main class="">
<div class="text-center p-8 bg-green-100">
<p class="">welkom</p>
<h2 class="text-3xl font-bold">{{ Auth::user()->name }}</h2>
</div>
<section class="bg-red-100">
<span class="p-4"><p class="text-center text-xl font-semibold">Mijn lijsten</p></span>
#foreach (auth()->user()->birthLists as $list)
<div class="bg-red-200 p-8 bg-gradient-to-b from-green-300 to-fuchsia-400 drop-shadow-xl text-white md:w-5/12 xl:w-3/12">
<div class="text-3xl font-bold">
{{ $list->baby }}
</div>
<div class="flex flex-row justify-between">
{{ $list->vader }} & {{ $list->moeder }}
</div>
</div>
#endforeach
</section>
</main>
#include('partials.footer')
</body>
and don't need to get data from controller because you can get birthLists in blade file.
in my livewire view i get all the credits from their respective owners through the model relationship between clients and credits
Model: Client
protected $fillable = ['name'];
public function credits(){
return $this->hasMany(Credit::class);
}
public function payments(){
return $this->hasManyThrough(Payment::class, Credit::class);
}
Model: Credit
const ACTIVE= 1;
const LIQUIDATED= 2;
protected $fillable = ['amount', 'amount_end', 'status', 'dues'];
public function client(){
return $this->belongsTo(Client::class);
}
public function provider(){
return $this->belongsTo(Provider::class);
}
public function payments(){
return $this->hasMany(Payment::class);
}
in my livewire view I have a foreach that gets me all the clients, inside a switch that counts the credits of the clients
Livewire: Show-client
#foreach ($clients as $item)
...
#switch($item->credits->count())
#case($status_credit = 1)
<span class="px-2 py-1 inline-flex text-sm leading-5 font-semibold rounded-md bg-yellow-300 text-yellow-600 geosanslgbold text-md">
Credit
</span>
#break
#case($status_credits >= 2)
<span class="px-2 py-1 inline-flex text-sm leading-5 font-semibold rounded-md bg-orange-300 text-orange-700 geosanslgbold text-md">
Credits
</span>
#break
#default
<span class="px-2 py-1 inline-flex text-sm leading-5 font-semibold rounded-md bg-green-400 text-green-900 geosanslgbold text-md">
Not Credits
</span>
#endswitch
#endforeach
So far everything is fine, it tells me the credits and tells me if it has or not.
now the credits have the option to place them as active or liquidated
How would I make my switch, instead of telling me all the client's credits, only take the active or in this case the ones with the number 1 and add the active credits
sorry for my bad english
I believe you are looking for what's called "local query scopes" : https://laravel.com/docs/9.x/eloquent#local-scopes
public function scopeIsLiquidated(Builder $query): Builder
{
return $query->where('status', LIQUIDATED);
}
Usage :
$clients = ...->isLiquidated()->...;
I have a page with multiple posts, each post has a location and department & title.
I implemented the search function for "word search" and it works fine, but in addition to this I have two Dropdown menus for location & department, they get their content from two different table.
I am kind of stuck and don't know why it doesn't work, here is my controller code:
public function index(Request $request)
{
$posts = Post::orderBy('titel')->get();
$standorts = Standort::orderBy('standort_name')->get();
$abteilungs = Abteilung::orderBy('abteilung_name')->get();
if ($request->filled('s') || $request->has('standort') || $request->has('abteilung')) {
$word = strtolower($request->get('s'));
$location = $request->standort;
$dep = $request->abteilung;
$query = strtolower($request->get('s'));
$posts = $posts->filter(function ($post) use ($dep, $word, $location) {
if (
Str::contains(strtolower($post->Titel), $word) ||
Post::where('standort_name') == $location
|| Post::where('abteilung_name') == $dep
) {
return true;
}
return false;
});
}
return view('posts.overview', [
'posts' => $posts,
'standorts' => $standorts,
'abteilungs' => $abteilungs,
]);
}
Here is my blade code:
<form class="mb-5 flex justify-left grid grid-cols-4 gap-x-20" action=" {{ route('overview') }}"
method="get">
<div class="w-full h-12 text-left col-start-1 col-end-1">
<input placeholder="Schlagwort" type="text" id="s" name="s" value="{{ request()->get('s') }}"
class="mb-2 w-full h-full bg-white bg-opacity-95 rounded focus:ring-2 border border-gray-300 focus:border-indigo-500 text-base outline-none text-gray-700 text-xl py-1 px-3 leading-8">
</div>
<div class="text-left mb-4 h-12">
<select name="abteilung" id="abteilung" class="h-full w-full flex justify-center bg-white bg-opacity-95 rounded focus:ring-2 border border-gray-300 focus:border-indigo-500 text-base outline-none text-gray-700 text-lg text-center leading-8">
<option selected="true" disabled="disabled">Abteilung</option>
#foreach($abteilungs as $abteilung)
<option value="{{ $abteilung->abteilung_name }}">{{ $abteilung->abteilung_name }}</option>
#endforeach
</select>
</div>
<div class="text-left mb-4 h-12">
<select name="standort" id="standort" class="h-full w-full flex justify-center bg-white bg-opacity-95 rounded focus:ring-2 border border-gray-300 focus:border-indigo-500 text-base outline-none text-gray-700 text-lg text-center leading-8">
<option selected="true" disabled="disabled">Standort</option>
#foreach($standorts as $standort)
<option value="{{ $standort->standort_name }}">{{ $standort->standort_name }}</option>
#endforeach
</select>
</div>
<button class="col-start-4 col-end-4 w-11/12 h-12 text-white text-2xl px-4 py-2 rounded text-base font-medium bg-gradient-to-r from-green-400 to-blue-500 float-right shadow transition duration-500 ease-in-out transform hover:-translate-y-1 hover:scale-100">
Suchen
</button>
</form>
When I dd this part:
$word = strtolower($request->get('s'));
$location = $request->standort;
$dep = $request->abteilung;
I get the correct attributes, for instance a word like "HR", a location like "Munich" and a department like "Finance".
When I perform the search though for a specific department all posts are gone.
Edit for clarity:
The goal is that a user can search for a word in a title, a location and department all in one request, and only the post where each is present gets shown.
Edit Relation Models:
Post Model:
class Post extends Model
{
use HasFactory;
/**
* The attributes that are mass assignable.
*
* #var string[]
*/
protected $fillable = [
'titel',
'startdate',
'enddate',
'beschreibung',
'standort',
'type_name',
'abteilung_name',
'kontakt',
'isActive',
'lebenslauf',
'zeugnisse',
'anschreiben',
'weitere_Doks',
'is_Permitted',
'job_start',
];
public function location() {
return $this->hasOne(Standort::class);
}
public function job_type() {
return $this->hasOne(Jobtypes::class);
}
}
Abteilung Model:
class Abteilung extends Model
{
use HasFactory;
/**
* The attributes that are mass assignable.
*
* #var string[]
*/
protected $fillable = [
'abteilung_name',
];
public function posts() {
return $this->hasMany(Post::class);
}
}
Standort Model:
class Standort extends Model
{
use HasFactory;
/**
* The attributes that are mass assignable.
*
* #var string[]
*/
protected $fillable = [
'abteilung_name',
];
public function posts() {
return $this->hasMany(Post::class);
}
}
I get a the below error when I try to update the modal text after a search performed
select * from [test] where [test].[id] in (?)
\vendor\laravel\framework\src\Illuminate\Database\Connection.php:703
I have added a primary key name in the model that is different. See the model class:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Test extends Model
{
use HasFactory;
/**
* The primary key associated with the table.
*
* #var string
*/
protected $primaryKey = 'testId';
/**
* Indicates if the model's ID is auto-incrementing.
*
* #var bool
*/
public $incrementing = false;
/**
* The data type of the auto-incrementing ID.
*
* #var string
*/
protected $keyType = 'string';
protected $connection = 'sqlsrv2';
protected $table = "test";
}
Here is the livewire class:
<?php
namespace App\Http\Livewire;
use App\Models\TestSubItems;
use App\Models\Test;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Livewire\Component;
class TestApp extends Component
{
use AuthorizesRequests;
public $search = '';
public $items = null;
public $subItems = null;
public $message = '';
public $warning = false;
public function render()
{
return view('livewire.bin-app');
}
public function search()
{
$this->items = null;
$this->subItems = null;
if ($this->search) {
$this->items = Test::where('ItemNo', $this->search)->get();
if (!$this->items->isEmpty()) {
$this->warning = false;
$this->message = '';
$this->subItems = TestSubItems::where('ItemNo', $this->search)->get();
}
if ($this->items->isEmpty()) {
$this->message = 'Not found';
}
}
}
}
Blade file:
<div>
<div class="grid grid-cols-1 gap-4 p-4">
<div>
<label for="search" class="text-right">Item Code: </label>
<input wire:model="search" autofocus="autofocus"
class="block appearance-none w-full bg-gray-200 border border-gray-200 text-gray-700 py-3 px-4 pr-8 rounded leading-tight focus:outline-none focus:bg-white focus:border-gray-500"
id=" search"
/>
</div>
#if ($message != '')
<div class="mb-5 mt-5 bg-red-50 rounded-md py-4 px-4">
<p class="font-bold text-green-500">
{{ $message }}
</p>
</div>
#endif
<div>
<button wire:click="search()" class="btn btn-primary">Search</button>
</div>
</div>
#if (isset($items))
#if (!$items->isEmpty())
<div class="grid grid-cols-1 gap-4 p-4">
#foreach($items as $item)
<h2 class="md:text-3xl text-xs"><span class="font-bold">Code:</span>
{{ $item->code }}
</h2>
#endforeach
</div>
#endif
#endif
#if (isset($subItems))
#if (!$subItems->isEmpty())
<table class="table w-full">
<thead>
<th class="border-2 border-gray-50">
Item No
</th>
<th class="border-2 border-gray-50">
Type
</th>
</thead>
<tbody>
#foreach($subItems as $item)
<tr>
<td class="border-2 border-gray-50">
{{ $item->itemNo }}
</td>
<td class="border-2 border-gray-50">
{{ $item->type }}
</td>
</tr>
#endforeach
</table>
#endif
#endif
</div>
This only happens after the initial search. I think it is related to the Model some way but not sure how.
Any help would be great to solve this.
I run your code, I only added to the TestSubItems the next properties
class TestSubItems extends Model
{
use HasFactory;
/**
* The primary key associated with the table.
*
* #var string
*/
protected $primaryKey = 'itemNo';
/**
* Indicates if the model's ID is auto-incrementing.
*
* #var bool
*/
public $incrementing = false;
/**
* The data type of the auto-incrementing ID.
*
* #var string
*/
protected $keyType = 'string';
}
While trying to create fake posts on laravel 8, I met with some errors, first it wasn't creating the posts, then I changed the username to nullable and it created it but I keep having;
Attempt to read property "username" on null
So, I went back to my database and I changed it back to none, but I still receive the same error code, I will post my codes now...
index.blade.php
#extends('layouts.app')
#section('content')
<div class="flex justify-center">
<div class="w-8/12 bg-white p-6 rounded-lg">
<form action="{{ route('posts') }}" method="post" class="mb-4">
#csrf
<div class="mb-4">
<label for="body" class="sr-only">Body</label>
<textarea name="body" id="body" cols="30" rows="4" class="by-gray-100 border-2
w-full p-4 rounded lg #error('body') border-red-500 #enderror" placeholder="Post something!"></textarea>
#error('body')
<div class="text-red-500 mt-3 text-sm">
{{$message}}
</div>
#enderror
</div>
<div>
<button type="submit" class="bg-blue-500 text-white px-4 py-2 rounded
font-medium">Post</button>
</div>
</form>
#if ($posts->count())
#foreach ($posts as $post)
<div class="mb-4">
{{ $post->user->username }}
<span class="text-gray-600 text-sm">{{ $post->created_at->diffForHumans() }}</span>
<p class="mb-2">{{ $post->body }}</p>
</div>
#endforeach
{{ $posts->links() }}
#else
There are no posts...
#endif
</div>
</div>
#endsection
UserFactory.php
<?php
namespace Database\Factories;
use App\Models\User;
use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Support\Str;
class UserFactory extends Factory
{
/**
* The name of the factory's corresponding model.
*
* #var string
*/
protected $model = User::class;
/**
* Define the model's default state.
*
* #return array
*/
public function definition()
{
return [
'username' => $this->faker->username,
'name' => $this->faker->name,
'email' => $this->faker->unique()->safeEmail,
'email_verified_at' => now(),
'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password
'remember_token' => Str::random(10),
];
}
/**
* Indicate that the model's email address should be unverified.
*
* #return \Illuminate\Database\Eloquent\Factories\Factory
*/
public function unverified()
{
return $this->state(function (array $attributes) {
return [
'email_verified_at' => null,
];
});
}
}
User.php
<?php
namespace App\Models;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
class User extends Authenticatable
{
use HasFactory, Notifiable;
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
'name',
'email',
'password',
'username',
];
/**
* The attributes that should be hidden for arrays.
*
* #var array
*/
protected $hidden = [
'password',
'remember_token',
];
/**
* The attributes that should be cast to native types.
*
* #var array
*/
protected $casts = [
'email_verified_at' => 'datetime',
];
public function posts(){
return $this->hasMany(Post::class);
}
}
PostFactory.php
<?php
namespace Database\Factories;
use App\Models\Post;
use Illuminate\Database\Eloquent\Factories\Factory;
class PostFactory extends Factory
{
/**
* The name of the factory's corresponding model.
*
* #var string
*/
protected $model = Post::class;
/**
* Define the model's default state.
*
* #return array
*/
public function definition()
{
return [
'body' => $this->faker->sentence(20),
];
}
}
Post.php
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Post extends Model
{
use HasFactory;
protected $fillable= [
'body',
'user_id',
];
/**
* Get the user that owns the Post
*
* #return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function user()
{
return $this->belongsTo(User::class);
}
}
It was because I had an existing user_id in my code so, I deleted it from the database and it worked