I have a Users table, a Images table and a Bookmarks table. I've specified the relationships for each one in my database and I am capable of accessing all the images that a user has uploaded. However I cannot access the images they have bookmarked.
This is what my databases relationships look like:
I am able to access the data I want using the SQL input on PHPMyAdmin however I cannot when using Laravel:
Using Laravel yields this error:
This is my User Model:
<?php
use Illuminate\Auth\UserInterface;
use Illuminate\Auth\Reminders\RemindableInterface;
use Cartalyst\Sentry\Users\Eloquent\User as SentryUserModel;
class User extends SentryUserModel implements UserInterface, RemindableInterface {
public $activated = true;
public function getAuthIdentifier() {
return $this->getKey();
}
public function getAuthPassword() {
return $this->password;
}
public function getRememberToken() {
return $this->remember_token;
}
public function setRememberToken($value) {
$this->remember_token = $value;
}
public function getRememberTokenName() {
return 'remember_token';
}
public function getReminderEmail() {
return $this->email;
}
public function images() {
return $this->hasMany('image', 'poster_id', 'id');
}
public function bookmarks() {
return $this->hasMany('bookmark', 'bookmarker_id', 'id');
}
}
This is my Image Model:
<?php
class Image extends Eloquent {
public function poster() {
return $this->belongsTo('user', 'poster_id', 'id');
}
}
This is my Bookmark Model:
<?php
class Bookmark extends Eloquent {
public $timestamps = false;
public function bookmarker() {
return $this->belongsTo('user', 'bookmarker_id', 'id');
}
public function image() {
return $this->hasOne('image', 'image_id', 'id');
}
}
This is the view in which the error is being thrown:
#extends('master')
#section('content')
<!-- Page Content -->
<header class="navbar navbar-inverse" role="navigation">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target=".navbar-collapse">
<span class="sr-only">Toggle Navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
Egami
</div>
<div class="collapse navbar-collapse">
<ul class="nav navbar-nav navbar-right">
#if(!Sentry::check())
<li>
Login
</li>
<li>
Signup
</li>
#endif
#if(Sentry::check())
#if(Sentry::getUser()->id == $user->id)
<li class="active">
#else
<li>
#endif
Profile
</li>
<li>
Logout
</li>
#endif
</ul>
</div>
</div>
</header>
<div class="container" id="profile">
<div class="row">
<div class="tac col-md-3">
<img src="/img/{{ $user->profile_image }}" alt="{{ $user->username }}'s Profile Image">
</div>
<div class="tal col-md-8">
<h2>{{ $user->username }}</h2>
</div>
</div>
<div class="row">
<div class="col-md-12">
<div class="navbar navbar-inverse" role="navigation">
<ul class="nav navbar-nav navbar-center">
<li>
Uploaded Images
</li>
<li class="active">
Bookmarked Images
</li>
</ul>
</div>
</div>
</div>
<div class="row">
<div class="col-md-12">
<div class="row">
<?php
$bookmarks = $user->bookmarks()->orderBy('id', 'DESC')->simplePaginate(15);
?>
#foreach($bookmarks as $bookmark)
<div class="col-md-4 user-image">
<a href="{{ URL::action('ImageController#show', $bookmark->image()->id) }}">
<img src="/uimg/{{ $bookmark->image()->id }}.png" alt="{{ $bookmark->image()->title }}">
</a>
</div>
#endforeach
</div>
<div class="row">
<div class="container">
{{ $bookmarks->links() }}
</div>
</div>
</div>
</div>
</div>
<footer class="navbar-fixed-bottom">
<div class="container">
<p>
Copyright © Egami {{ date('Y') }}
</p>
</div>
</footer>
#stop
#section('scripts')
#stop
Try this:
<a href="{{ URL::action('ImageController#show', $bookmark->image->id) }}">
<img src="/uimg/{{ $bookmark->image->id }}.png" alt="{{ $bookmark->image->title }}">
</a>
Removed parentheses $bookmark->image()->id to $bookmark->image->id.
Related
//here is my controller `
public function index($id){
$users=User::where('id',$id)->get();
return view('user',compact('users'));
}
}`
//here is my User model
public function getPosts()
{
return $this->hasMany('App\Post','user_id','id');
}
//here is my user blade
#foreach($user->getPosts as $post)
<div class="profile-content">
<section class="post-heading">
<div class="rows">
<div class="col-md-11">
<div class="media">
<div class="media-left">
<a href="#">
<img class="media-object photo-profile" src="https://scontent.fgyd4-2.fna.fbcdn.net/v/t1.0-9/p960x960/73248174_2597397730318615_6397819353256951808_o.jpg?_nc_cat=109&_nc_sid=7aed08&_nc_ohc=VxH_cAqJ778AX_7B97W&_nc_ht=scontent.fgyd4-2.fna&_nc_tp=6&oh=e5b02c7f91818664cf253e71f2ddf106&oe=5F5F4E74" width="40" height="40" alt="...">
</a>
</div>
<div class="media-body">
<h4 class="media-heading">{{$user->name}} </h4>
{{$user->$post['created_at']}}
</div>
</div>
</div>
<div class="col-md-1">
<i class="glyphicon glyphicon-chevron-down"></i>
</div>
</div>
</section>
<section class="post-body">
<p>{{ $user->getPost->post['post_description'] }}</p> <!-- i stick around here -->
</section>
//it give this error to me
Property [getPosts] does not exist on this collection instance. (View: C:\xampp\htdocs\site\resources\views\user.blade.php)
In controller get() will return collection,you want one user, so use find() or first(), it will return one user object
public function index($id){
$user=User::find($id); //or $user=User::where('id',$id)->first();
return view('user',compact('user'));
}
Relation method
public function posts()
{
return $this->hasMany('App\Post','user_id','id');
}
Since their is one to many relation between user and posts,you have to use loop to show posts for a user
foreach($user->posts as $post)
<div class="profile-content">
<section class="post-heading">
<div class="rows">
<div class="col-md-11">
<div class="media">
<div class="media-left">
<a href="#">
<img class="media-object photo-profile" src="https://scontent.fgyd4-2.fna.fbcdn.net/v/t1.0-9/p960x960/73248174_2597397730318615_6397819353256951808_o.jpg?_nc_cat=109&_nc_sid=7aed08&_nc_ohc=VxH_cAqJ778AX_7B97W&_nc_ht=scontent.fgyd4-2.fna&_nc_tp=6&oh=e5b02c7f91818664cf253e71f2ddf106&oe=5F5F4E74" width="40" height="40" alt="...">
</a>
</div>
<div class="media-body">
<h4 class="media-heading">{{$user->name}} </h4>
{{$post->created_at}}
</div>
</div>
</div>
<div class="col-md-1">
<i class="glyphicon glyphicon-chevron-down"></i>
</div>
</div>
</section>
<section class="post-body">
<p>{{ $post->post_description }}</p> <!-- i stick around here -->
</section>
#endforeach
$users=User::where('id',$id)->get(); returns a collection of users
So when you do this:
#foreach($user->getPosts as $post)
$user is a collection of users. That collection doesn't have a getPosts() method.
you are returning list of users, so you don't have one user and you can't have the posts of all certain user
below code can fix the issue:
User::where('id', $id)->first();
First of all you should update your controller like this
User::find($id);
You should update your relation like this
public function posts()
{
return $this->hasMany('App\Post','user_id','id');
}
After that you should update your blade like this
foreach ($user->posts as $post)
You can't access posts with ->getPosts. If you want, you should use like this ->getPosts()->get()
I have a books table and a image table and I also going to have a blog table in future. That's why I want to create a polymorphic relation between book,blog and image table. but my problem is when I tired to retrive data of book image url from the relationship in view home.blade.php with #foreach I am getting this :
Call to a member function getImage() on null (View: F:\xampp\htdocs\BookReader\resources\views\Main_pages\includes\Home\new_product.blade.php)
codes are given bellow:
home.blade.php
#extends('Main_pages.app')
#section('title','Home')
#section('content')
#include('Main_pages.includes.Home.new_product')
#include('Main_pages.includes.Home.testimonial')
#include('Main_pages.includes.Home.popular_products')
#include('Main_pages.includes.Home.news_letter')
#include('Main_pages.includes.Home.blogs')
#include('Main_pages.includes.Home.quick_view')
#endsection
new_product.blade.php
<section class="wn__product__area brown--color pt--80 pb--30">
<div class="container">
<div class="row">
<div class="col-lg-12">
<div class="section__title text-center">
<h2 class="title__be--2">New <span class="color--theme">Products</span></h2>
<p>There are many variations of passages of Lorem Ipsum available, but the majority have suffered lebmid alteration in some ledmid form</p>
</div>
</div>
</div>
<!-- Start Single Tab Content -->
<div class="furniture--4 border--round arrows_style owl-carousel owl-theme row mt--50">
#foreach($new_books as $book)
<!-- Start Single Product -->}}
<div class="product product__style--3">
<div class="col-lg-3 col-md-4 col-sm-6 col-12">
<div class="product__thumb">
<a class="first__img" href="single-product.html"><img src="{{$book->image->getImage()}}" alt="product image"></a>
<div class="hot__box">
<span class="hot-label">BEST SALLER</span>
</div>
</div>
<div class="product__content content--center">
<h4>{{$book->title()}}</h4>
<ul class="prize d-flex">
<li>$35.00</li>--}}
<li class="old_prize">$35.00</li>
</ul>
<div class="action">
<div class="actions_inner">
<ul class="add_to_links">
<li><a class="cart" href="cart.html"><i class="bi bi-shopping-bag4"></i></a></li>
<li><a class="wishlist" href="wishlist.html"><i class="bi bi-shopping-cart-full"></i></a></li>
<li><a class="compare" href="#"><i class="bi bi-heart-beat"></i></a></li>
<li><a data-toggle="modal" title="Quick View" class="quickview modal-view detail-link" href="#productmodal"><i class="bi bi-search"></i></a></li>
</ul>
</div>
</div>
<div class="product__hover--content">
<ul class="rating d-flex">
<li class="on"><i class="fa fa-star-o"></i></li>
<li class="on"><i class="fa fa-star-o"></i></li>
<li class="on"><i class="fa fa-star-o"></i></li>
<li><i class="fa fa-star-o"></i></li>
<li><i class="fa fa-star-o"></i></li>
</ul>
</div>
</div>
</div>
</div>
<!-- Start Single Product -->
#endforeach
</div>
<!-- End Single Tab Content -->
</div>
images migration
public function up()
{
Schema::create('images', function (Blueprint $table) {
$table->id();
$table->text('url');
$table->unsignedBigInteger('imageable_id');
$table->text('imageable_type');
$table->timestamps();
});
}
books migration
public function up()
{
Schema::create('books', function (Blueprint $table) {
$table->id();
$table->string('book_title');
$table->string('book_author');
$table->text('book_description');
$table->timestamps();
});
}
Image Model
class Image extends Model
{
public function imageable(){
return $this->morphTo();
}
public function getImage(){
return $this->url;
}
}
Book Model
class Book extends Model
{
public function image(){
return $this->morphOne(Image::class,'imageable');
}
public function title(){
return $this->book_title;
}
public function author(){
return $this->book_author;
}
public function desc(){
return $this->book_description;
}
}
HomeController
class HomeController extends Controller
{
public function view(){
$new_books = Book::latest()->get();
return view('Main_pages.Pages.home',['new_books'=>$new_books]);
}
}
It is obvious. There is a book without any image.
Change the img code to this:
#isset ($book->image)
<img src="{{$book->image->getImage()}}" alt="product image">
#endisset
or use optional method and Null Coalesce Operator to have a default image:
<img src="{{optional($book->image)->getImage() ?? 'default_image_path.png'}}" alt="product image">
or this one:
#if (isset($book->image))
<img src="{{$book->image->getImage()}}" alt="product image">
#else
<img src="default_image_path.png" alt="product image">
#endif
I hope this helps you.
PostController.php
public function index($id)
{
$post = Post::where('post_id', $id)->first();
$categories = DB::table('categories')->select('name AS category_name', 'slug AS category_slug', 'category_id AS cid')->get();
return view('post', compact('post','categories'));
}
post.blade.php
<div class="accordion sticky-top" id="sideNavigation" style="top:55px">
#foreach($categories as $category)
<?php $posts_list = DB::table('posts')->join('categories', 'categories.category_id', 'posts.category_id')
->where('posts.category_id', $category->cid)
->get();
?>
<h2 class="mb-0 border-bottom py-2 ">
<button class="btn btn-link" type="button" data-toggle="collapse"
data-target="#{{$category->category_slug}}" aria-expanded="true"
aria-controls="{{$category->category_slug}}">
{{ $category->category_name}}
</button>
</h2>
<div id="{{$category->category_slug}}" class="collapse" aria-labelledby="headingOne"
data-parent="#sideNavigation">
<div class="card-body">
<ul class="list-unstyled">
#foreach($posts_list as $post_list)
<li>{{$post_list->title}}</li>
#endforeach
</ul>
</div>
</div>
#endforeach
</div>
The idea is so have this:
Category
Post
Post
Post
Category 2
Post
Post
My current solution works but I can see this becoming a problem very quickly to maintain.
You need to add relationships to your models. Documentation is here.
Providing its a one to many relationship you would do the following
In your Category model
public function posts()
{
return $this->hasMany('App\Post', 'category_id', 'category_id');
}
In your Post model
public function category()
{
return $this->hasOne('App\Category', 'category_id', 'category_id');
}
Then you can clean up your view
<div class="accordion sticky-top" id="sideNavigation" style="top:55px">
#foreach($categories as $category)
<h2 class="mb-0 border-bottom py-2 ">
<button class="btn btn-link" type="button" data-toggle="collapse" data-target="#{{$category->category_slug}}" aria-expanded="true" aria-controls="{{$category->category_slug}}">{{ $category->category_name}}</button>
</h2>
<div id="{{$category->category_slug}}" class="collapse" aria-labelledby="headingOne" data-parent="#sideNavigation">
<div class="card-body">
<ul class="list-unstyled">
#foreach($category->posts as $post)
<li>{{$post->title}}</li>
#endforeach
</ul>
</div>
</div>
#endforeach
</div>
I would also think this line is not the best way of going about it, you will likely need a route applying
<a href="{{ $post->post_id}}">
I am using Laravel Commentable package which uses Nested Sets pattern with Baum.
I have managed to allow users to make comments on posts but they're not threaded, each comment has depth set to zero in the database.
So I'm wondering how does one go about making multi threaded comments like reddit for example?
These are my tables
users: id, name, email...
posts: id, user_id, subreddit_id...
comments: id, body, parent_id, lft, rgt, depth, commentable_id, commentable_type, user_id
My Models (Comment and User)
class Comment extends Model
{
use Commentable;
public function commentable()
{
return $this->morphTo();
}
public function user() {
return $this->belongsTo('App\User');
}
public function posts() {
return $this->belongsTo('App\Post');
}
}
class User extends Model implements AuthenticatableContract, AuthorizableContract, CanResetPasswordContract
{
use Authenticatable, Authorizable, CanResetPassword;
public function posts() {
return $this->hasMany('App\Post');
}
public function comments() {
return $this->hasMany('App\Comment');
}
}
This is how I'm submitting comments in PostsController
public function createComment($id) {
$post = Post::with('user.votes')->with('subreddit.moderators')->where('id', $id)->first();
$comment = new Comment;
$comment->body = Input::get('comment');
$comment->user_id = Auth::id();
$post->comments()->save($comment);
}
And this is the view
<div class="post-comments">
{!! Form::open(['route' => ['comment', $post]]) !!}
<div class="form-group">
<label for="comment">Your Comment</label>
<textarea name="comment" class="form-control" rows="3"></textarea>
</div>
<button type="submit" class="btn btn-default">Send</button>
{!! Form::close() !!}
<div class="comments-nav">
<ul class="nav nav-pills">
<li role="presentation" class="dropdown">
<a class="dropdown-toggle" data-toggle="dropdown" href="#" role="button" aria-haspopup="true" aria-expanded="false">
there are {{ count($comments) }} comments <span class="caret"></span>
</a>
<ul class="dropdown-menu">
<li>Best</li>
<li>Hot</li>
</ul>
</li>
</ul>
</div>
<div class="row">
<div class="media">
<!-- first comment -->
#foreach($comments as $comment)
<div class="media-heading">
<button class="btn btn-default btn-xs" type="button" data-toggle="collapse" data-target="#{{ $comment->id }}" aria-expanded="false" aria-controls="collapseExample"><span class="glyphicon glyphicon-minus" aria-hidden="true"></span></button> <span class="label label-info">12314</span> {{ $comment->user->name }} 12 hours ago
</div>
<div class="panel-collapse collapse in" id="{{ $comment->id }}">
<div class="media-left">
<div class="vote-wrap">
<div class="vote up">
<i class="glyphicon glyphicon-menu-up"></i>
</div>
<div class="vote inactive">
<i class="glyphicon glyphicon-menu-down"></i>
</div>
</div>
<!-- vote-wrap -->
</div>
<!-- media-left -->
<div class="media-body">
<p>{{ $comment->body }}</p>
<div class="comment-meta">
<span>delete</span>
<span>report</span>
<span>hide</span>
<span>
<a class="" role="button" data-toggle="collapse" href="#replyCommentT" aria-expanded="false" aria-controls="collapseExample">reply</a>
</span>
<div class="collapse" id="replyCommentT">
<form>
<div class="form-group">
<label for="comment">Your Comment</label>
<textarea name="comment" class="form-control" rows="3"></textarea>
</div>
<button type="submit" class="btn btn-default">Send</button>
</form>
</div>
</div>
<!-- comment-meta -->
</div>
</div>
<!-- comments -->
#endforeach
</div>
<!-- first comment -->
</div>
</div>
<!-- post-comments -->
I haven't used Laravel Commentable package, but the docs look pretty good.
I believe you need use Commentable; on your Post model and not your Comment model.
It looks like your Comment model needs to extend Baum\Node and not Model
Then what you have should work.
$post = Post::with('user.votes')->with('subreddit.moderators')->where('id', $id)->first();
$comment = new Comment;
$comment->body = Input::get('comment');
$comment->user_id = Auth::id();
$post->comments()->save($comment);
// or you could do
$comment->makeChildOf($post);
To make a comment on a comment, it looks like you do something like this. I would probably make a CommentsController.
public function addComment(Request $request){
$parent = Comment::find(Input::get('parent_id'));
$comment = new Comment;
$comment->body = Input::get('comment');
$comment->user_id = Auth::id();
$comment->makeChildOf($parent);
}
The Relations, Root and Leaf scopes, Accessing the ancestry/descendancy chain section of the docs have several examples on how to then retrieve the comments for comments.
Edit
It looks like the Comment model in the package already extends the Baum\Node so you don't need to do that. In order to use this package, it looks like you need to use his Comment model. I am sure you could use his model as a base and roll your own.
You could do something like this. You would have to set up a route.
<div class="collapse" id="replyCommentT">
{!! Form::open(['route' => ['comment', $comment]]) !!}
<input type="hidden" name="parent_id" value="{{ $comment->id }}"/>
<div class="form-group">
<label for="comment">Your Comment</label>
<textarea name="comment" class="form-control" rows="3"></textarea>
</div>
<button type="submit" class="btn btn-default">Send</button>
{!! Form::close() !!}
</div>
How can I call a method of a controller from blade template and receive the data is returned by the method. For Example:
MeetingRoomController
class MeetingRoomController extends \BaseController
{
public function index()
{
//get all the meeting room
$meetingRoomCountry = MeetingRoom::select('country')->distinct()->orderBy('country')->get();
return View::make('index')->with('meetingroom', $meetingRoomCountry);
}
public function findLocationForNavBar( $country )
{
$meetingRoomLocation = MeetingRoom::select('location')
->distinct()
->where('country', '$country')
->orderBy('country')
->get();
return View::make('index')- >with('meetingroomLocation', $meetingRoomLocation);
}
}
View - index.blade.php
<div id="dropdown-lvl1" class="panel-collapse collapse">
<div class="panel-body">
<ul class="nav navbar-nav">
#foreach($meetingroom as $key => $value)
<li class="panel panel-default" id="dropdown">
<a data-toggle="collapse" href="#dropdown-lvl2">
<span class="glyphicon glyphicon-off"></span> {{$country = $value->country}} <span class="caret"></span>
</a>
<div id="dropdown-lvl2" class="panel-collapse collapse">
<div class="panel-body">
<ul class="nav navbar-nav">
<li>Location</li>
</ul>
</div>
</div>
</li>
#endforeach
</ul>
</div>
</div>
I want to collect the location based on corresponding country. According to my logic, First of all I collected the distinct country then searched the location by findLocationForNavBar method in MeetingRoomController.
If you're using Laravel 5.1, you could try a Service Injection from your blade template.
http://laravel.com/docs/5.1/blade#service-injection
Example from the docs:
#inject('metrics', 'App\Services\MetricsService')
<div>
Monthly Revenue: {{ $metrics->monthlyRevenue() }}.
</div>
You can do all this stuff in the index() method and send location and country to view.