What I'm trying to achieve is post all news by #foreach and between the #foreach do another #foreach to post all comments with the ID from the news post.
I'm unsure on how to pass this ID, to the getNewsComments function.
My controller:
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use DB;
use App\News;
use App\newsComments;
class newsController extends Controller
{
public function getAllNews(){
$results = News::all();
return view('index')->with('news', $results);
}
}
Route:
Route::get('/', 'newsController#getAllNews');
News model:
class News extends Model
{
// set table
protected $table = 'lg_news';
public function newsComments(){
return $this->hasMany('App\newsCommments');
}
}
Comment model:
class newsComments extends Model
{
// set table name
protected $table = 'lg_newscomments';
}
view
#foreach ($news as $article)
#foreach($news->$newsComments as $comment)
#endforeach
#endforeach
Error:
Undefined variable: newsComments (View:
C:\xampp\htdocs\resources\views\index.blade.php)
Change this line:
return view('index')->with('news', $results);
to
return view('index', ['news' => $results]);
and it probably will work.
PS: with() function will set a session! It will not pass a variable to view.
You don't need multiple routes you just need to have two tables related to each other with 1:N relationship
Article (1) -> Comments (N)
Then you will create a model for each table and create the relation like explained in the Laravel documentation
One to Many relationship in Laravel
Then you will fetch all posts and pass them to the view:
public function getAllArticles()
{
$posts = Post::all();
return view('view-name', $posts);
}
And at the end, create a view and show posts and comments:
#foreach($posts as $post)
{{ $post->title }}
{{ $post->body }}
#foreach($post->comments as $comment)
{{ $comment->title }}
{{ $comment->body }}
#endforeach
#endforeach
Reminder: $post->comments , comments is the method name defined in the model where you create the relationship
Define route at web.php:
Route::get('/', 'ControllerName#getAllArticles');
Go to localhost:8000/ (or to your site domain if the site is hosted) to see the result
Related
I'm trying to do a search input from 2 datatables of my database, one containing vegetables and the other one containing recipes made of vegetables, i first made my search input with only the elements from the vegetable table. But now im trying to include the repice table but it wont work: I'm getting the error "Attempt to read property "recipes" on array" but I do't understand where the problem comes from.
This is my code:
Search.php:
<?php
namespace App\Http\Livewire;
use Livewire\Component;
use App\Models\Vegetable;
class Search extends Component
{
public $query = '';
public $vegetables;
public $recipes;
public function updatedQuery()
{
$this->vegetables = Vegetable::where('name', 'like', '%'.$this->query.'%')->get()->toArray();
}
public function render()
{
return view('livewire.search');
}
}
search.blade.php :
<div class="searchcomponent">
<h1>Recherche</h1>
<input wire:model="query" type="text" placeholder="Rechercher...">
#if(!empty($query))
<ul>
#if(!empty($vegetables))
<div class="vegetables">
#foreach($vegetables as $vegetable)
<li><span class="material-icons">lunch_dining</span>{{ $vegetable['name'] }}</li>
#endforeach
</div>
#else
<li>Pas de résultat</li>
#endif
<div class="recipes">
#foreach($vegetables as $vegetable)
#foreach($vegetable->recipes as $recipe)
<li><span class="material-icons">menu_book</span>{{ $recipe['name'] }}<span class="ingredient">Ingrédient: {{ $vegetable['name'] }}</span></li>
#endforeach
#endforeach
</div>
</ul>
#endif
</div>
My model Vegetable :
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Vegetable extends Model
{
use HasFactory;
public $timestamps = false;
protected $fillable = ['name'];
public function recipes(){
return $this->belongsToMany(Recipe::class, 'vegetables_recipes', 'vegetable_id', 'recipe_id');
}
public function getName($id) {
return $this->name;
}
}
My model Recipe :
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Recipe extends Model
{
use HasFactory;
public $timestamps = false;
protected $fillable = ['name'];
public function vegetables(){
return $this->hasOne(Vegetable::class, 'vegetables_recipes', 'recipe_id', 'vegetable_id');
}
public function getName($id) {
return $this->name;
}
}
The model from my pivot table VegetablesRecipe :
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class VegetablesRecipe extends Model
{
use HasFactory;
public $timestamps = false;
protected $fillable = ['vegetable_id', 'recipe_id'];
}
Thank you in advance
So I found the issue with your code; I didn't notice it yesterday as it was hidden off-screen in your Search.php's updatedQuery() function:
$this->vegetables = Vegetable::where('name', 'like', '%'.$this->query.'%')
->get()
->toArray();
When you call ->toArray(), you convert the Collection of Vegetable Model instances into an Array of Arrays. This means you cannot use Object Access to get Properties:
$vegetable->recipes; // Fails with error "Attempt to read property "recipes" on array"
Additionally, you cannot access any Model functions, as an Array is not an instance of a Model:
$vegetables['recipes']; // Undefined array key "recipes"
Since public function recipes() is a method of the Vegetable.php Model class, that won't work. It can work, if you load it first before casting to an Array:
$this->vegetables = Vegetable::where('name', 'like', '%'.$this->query.'%')
->with('recipes')
->get()
->toArray();
Now, $vegetable['recipes'] will work, but it's better to just drop the ->toArray() completely:
$this->vegetables = Vegetable::where('name', 'like', '%'.$this->query.'%')
->with('recipes')
->get();
Additionally, for performance reasons, you want to include ->with('recipes') to prevent N+1 queries being called while looping.
With those changes made, you can write your livewire/search.blade.php code as follows:
<div class="searchcomponent">
<h1>Recherche</h1>
<input wire:model="query" type="text" placeholder="Rechercher...">
#if(!empty($query))
<ul>
#if(!empty($vegetables))
<div class="vegetables">
#foreach($vegetables as $vegetable)
<li><span class="material-icons">lunch_dining</span>{{ $vegetable->name }}</li>
#endforeach
</div>
#else
<li>Pas de résultat</li>
#endif
<div class="recipes">
#foreach($vegetables as $vegetable)
#foreach($vegetable->recipes as $recipe)
<li><span class="material-icons">menu_book</span>{{ $recipe->name }}<span class="ingredient">Ingrédient: {{ $vegetable->name }}</span></li>
#endforeach
#endforeach
</div>
</ul>
#endif
</div>
Lastly, some cleanup:
Vegetable.php and Recipe.php
The methods getName($id) have no purpose; you're not doing anything with $id, and name is not a private property; you can simply do $vegetable->name or $recipe->name and it will do the same as what these methods are doing.
Recipe.php
As stated in the comments, belongsToMany() is the inverse of belongsToMany(), not hasOne():
public function vegetables(){
return $this->belongsToMany(Vegetable::class, 'vegetables_recipes');
}
Additionally, if the primary and foreign key names match the model names, you don't need them. The proper name for the pivot table would be recipes_vegetables (plural, alphabetical), so specifying that is required. You can do the same for Vegetable.php:
public function recipes(){
return $this->belongsToMany(Recipe::class, 'vegetables_recipes');
}
Lastly, your model VegetablesRecipe.php is not needed, and is currently not being used. You typically don't define a Model for a Pivot table, so you can either remove it, or keep it around should you ever need to directly modify the Pivot.
Here is the Controller code I have
public function index()
{
$ajobs = Job::all();
return view('jobs_all', ['jobs' => $ajobs]);
}
This shows all my Table Data. I have stored user id as another column named created_by
In the View, I get value by ID, how how can I get the Username from Users table.
#foreach ($jobs as $ajob)
{{ $ajob->created_by }} //Here instead of UserID, how can i get Username by matching the UserID with UsersTable ?
#endforeach
Add next method to your "Job" model:
public function user(): BelongsTo
{
return $this->belongsTo(User::class, 'created_by');
}
now you can add ORM param "with" to your method "index":
public function index() {
$ajobs = Job::with('user')
->all();
return view('jobs_all', ['jobs' => $ajobs]); }
now we have access to user model fields, and you can show them this way:
#foreach($jobs as $ajob)
{{ $ajob->user->name }}
#endforeach
More info about laravel relations here: https://laravel.com/docs/8.x/eloquent-relationships#one-to-one
you can use laravel eloquent belongsTo relationship. in your Job model add the following method.
public function user()
{
return $this->belongsTo(User::class, 'created_by');
//assuming your user model name is User and both models are in the same namespace. if not, adjust according to your structure.
}
and then you can use this relationship to get the user name like
#foreach ($jobs as $ajob)
{{ $ajob->user->name }}
//name is the column name from the user table. change if necessary.
#endforeach
You can use relations but in fast way on your situation you can join your tables:
$user_id = DB::table('jobs')
->select('users.id')
->join('jobs', 'jobs.user_id', '=', 'users.id')
->get();
=> add on your job table as foreginId user
$table->timestamp('created_at')->useCurrent();
$table->foreignId('created_by')->constrained('users')->onUpdate('cascade')->onDelete('cascade');
**That Function add on job model**
public function getCreatedAttribute()
{
return ucfirst($this->user->name);
}
=>relationship add on job table
public function user()
{
return $this->belongsTo(User::class,'id','created_by');
}
=>created display your user name
#foreach ($jobs as $ajob)
{{ $ajob->created}}
#endforeach
=>listing controller
public function index() {
$jobs = Job::with(['user']);
return view('jobs_all', compact('jobs')); }
So i was trying to get a full post from the database by id, so when i click this link Lanjutkan Baca <img src="asset/img/icons/double-arrow.png" alt="#"/> it will take me to the url /post/read/{id} and give me the fullpost, but it shows that error,
i search for the same problem and found that that the problem is $blogs variable is an array, but the value it return is not, can anybody show me how to make the method or the view in my code to return an array and show the full post ?
this is my view read.blade.php
#foreach ($blogs as $blog)
<div class="top-meta">{{ Carbon\Carbon::parse($blog->created_at)->format('d-m-Y') }} / di Rakitan</div>
<h3>{{ $blog->name }}</h3>
<p>{!! $blog->message !!}</p>
#endforeach
this is my BlogController.php
public function getFullPost($blog_id) {
$blogs = Blog::all()->where('blogs.id', '=', $blog_id)->first();
return view('post.read')->with(compact('blogs'));
}
this is the model Blog.php
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Blog extends Model
{
protected $fillable = ['name','message'];
}
and this is the routes
Route::get('/post/read/{blog_id}', 'BlogController#getFullPost')->name('post.read');
Use 'get' method to get all rows with cobditions
public function getFullPost($blog_id) {
$blogs = Blog::where('id', '=', $blog_id)->get();
return view('post.read')->with(compact('blogs'));
}
Add table name in Model to reference in Blog model
hi i am using a custom repository and I am getting comfortable with querying one table to retrieve data like so:
public function getAll()
{
// get all logged in users projects order by project name asc and paginate 9 per page
return \Auth::user()->projects()->orderBy('project_name', 'ASC')->paginate(9);
}
and in my controller I simply call
public function __construct(ProjectRepositoryInterface $project) {
$this->project = $project;
}
public function index()
{
$projects = $this->project->getAll();
echo View::make('projects.index', compact('projects'));
}
and my view is as so:
#if (Auth::check())
#if (count($projects) > 0)
#foreach ($projects as $project)
{{ $project->project_name }}
#endforeach
#else
<p>No records, would you like to create some...</p>
#endif
{{ $projects->links; }}
#endif
However within my projects table I have a status_id and a client_id and I want to retrieve records of this these tables with the logged in user but I am not sure how to structure my query, does anyone have any guidance?
According to the laravel documentation, In your project model you can add the following function:
class Project extends Eloquent
{
public function clients()
{
return $this->hasMany(Client::class);
}
}
In your client model you can then add the inverse of the relationship with the function:
class Client extends Eloquent
{
public function project()
{
return $this->belongsTo(Project::class);
}
}
Then you can retrieve the data with a function like:
$clients = Project::find(1)->clients;
Okay so I just started learning Laravel and its fantastic. I just got stuck trying to retrive all the post from a user. Here is my code
models/User.php
public function posts()
{
$this->hasMany('Post');
}
models/Post.php
public function user()
{
$this->belongsTo('User');
}
controller/UserController.php
public function getUserProfile($username)
{
$user = User::where('username', '=', $username)->first();
$this->layout->content = View::make('user.index', array('user'=>$user));
}
views/user/index.blade.php
<div class="show-post">
<ul>
<li>{{ $user->posts }}</lo>
</ul>
</div>
I also tried:
#foreach($user->posts as $post)
<li>{{$post->post}}</li>
#endforeach
So im having trouble displaying the post for each specific user. Thank you.
So with the help of #WereWolf- The Alpha I was able to solve it and make my code better, If you notice I forgot to return my relationship functions. example:
Notice I hadn't returned it before
models/Post.php
public function users()
{
return $this->belongsTo('users');
}
But also the way I was querying my database was inefficient so Alpha showed me Eager Loading
http://laravel.com/docs/eloquent#eager-loading
example of controller
public function getUserProfile($username)
{
$user = User::with('posts')->where('username', '=', $username)->first();
$this->layout->content = View::make('user.index', array('user'=>$user));
}
and finally the view:
div class="show-post">
#foreach($user->posts as $post)
{{ $post->post }}
#endforeach
</div>
Actually $user->posts returns a collection of Post model so when you try this
{{ $user->posts }}
Laravel tries to echo that collection object which is not possible. You may try foreach loop instead:
#foreach($user->posts as $post)
{{ $post->somepropertyname }}
#endforeach
It's also possible to do something like this:
// Get first post->somepropertyname
{{ $user->posts->first()->somepropertyname }}
// Get last post->somepropertyname
{{ $user->posts->last()->somepropertyname }}
// Get first post->somepropertyname (same as first)
{{ $user->posts->get(0)->somepropertyname }}
// Get second post->somepropertyname from collection
{{ $user->posts->get(1)->somepropertyname }}
// Get the post->somepropertyname by id (post id) 2
{{ $user->posts->find(2)->somepropertyname }}
Also you may use eager loading like this (better):
$user = User::with('posts')->where('username', '=', $username)->first();
You may like this article about Cocllection.
Update: Also use return in model methods, like:
public function posts()
{
return $this->hasMany('Post');
}