How to display default image if no filename exists in Laravel database - laravel

I want to display an image for each entry in a list of posts. The name of the images are unique file names. They are all saved in a database (MySQL) table. There is more than one image for each post. The code works right. Except, when there is a post without an image filename. This is a possible scenario but i can't get the code to work. In the event there's no existing filename for a post, i want to display a default filename.
Here's my code:
Images logic:
/**
* Get a vehicle's top or main image data from the image table
*/
public function topImage($id)
{
$image = Vehiclefulldataimage::where('vehiclefulldatas_id', $id)
->orderBy('id', 'ASC')->first();
return $image;
}
Here's the blade view, Posts:
#if (count($posts) > 0)
#foreach($posts as $post)
<?php $imageFilename = (new \App\Models\Logic\Images)->topImage($post->id); ?>
<!--Item-->
<li>
<div class="preview">
#if ($imageFilename = 0)
<img src="{{ asset('images') . '/' . 'defaultImage.jpg' }}" alt="No photo">
#else
<img src="{{ asset('images') . '/' . $imageFilename->disk_image_filename }}" alt="{{ ucfirst($imageFilename->caption) . ' | ' . $post->title }}">
#endif
</div>
<div class="desc">
<h3>{{ str_limit($post->title, 100, '...') }}</h3>
</div>
</li>
<!--/Item-->
#endforeach
#endif
This is the error message i get:
"Trying to get property of Non Object"

Try the following code:
You are using an assignment operator instead of comparison operator
//#if (count($posts) > 0)
#if (!$posts->isEmpty())
#foreach($posts as $post)
<?php $imageFilename = (new \App\Models\Logic\Images)->topImage($post->id); ?>
<!--Item-->
<li>
<div class="preview">
//#if ($imageFilename = 0) this is an assignment operator not comparison operator
#if ($imageFilename->isEmpty())
<img src="{{ asset('images') . '/' . 'defaultImage.jpg' }}" alt="No photo">
#else
<img src="{{ asset('images') . '/' . $imageFilename->disk_image_filename }}" alt="{{ ucfirst($imageFilename->caption) . ' | ' . $post->title }}">
#endif
</div>
<div class="desc">
<h3>{{ str_limit($post->title, 100, '...') }}</h3>
</div>
</li>
<!--/Item-->
#endforeach
#endif

Check your if statement....what you're doing there is an assignment and not a condition test...you can include a column..with a string pointing to the path of your default image..and set it to default...then load it...as default image

All of the answers above fix your problem. However, I recommend you to fix this problem by using Laravel features, Mutators.
https://laravel.com/docs/5.8/eloquent-mutators
Laravel mutators allow you to format or modify your Model attribute.
Just in your Vehiclefulldataimage model write the code below:
public function getImageAttribute($value)
{
//can write more logic here.
return $value ?: 'path/to/your/default/image';
}
Then you don't care more if condition blade template. If your image is empty the mutator returns the default image. So, everywhere when your retrieve Vehiclefulldataimage instance the mutator works properly

Thanks everyone.
After looking at all the answers, i did a simple alteration to my code. I altered:
#if ($imageFilename = 0)
to:
#if ($imageFilename == null)
Thus, my code now looks:
#if (count($posts) > 0)
#foreach($posts as $post)
<?php $imageFilename = (new \App\Models\Logic\Images)->topImage($post->id); ?>
<!--Item-->
<li>
<div class="preview">
#if ($imageFilename == null)
<img src="{{ asset('images') . '/' . 'defaultImage.jpg' }}" alt="No photo">
#else
<img src="{{ asset('images') . '/' . $imageFilename->disk_image_filename }}" alt="{{ ucfirst($imageFilename->caption) . ' | ' . $post->title }}">
#endif
</div>
<div class="desc">
<h3>{{ str_limit($post->title, 100, '...') }}</h3>
</div>
</li>
<!--/Item-->
#endforeach
#endif

Related

Searching in Laravel

I created a simple search in Laravel, to find stuff by search term
Controller
public function search()
{
$search = request()->query('search');
$data = array();
$data['books'] = Book::where('name', 'LIKE', "%{$search}%")->simplepaginate(12);
$data['authors'] = Author::where('name', 'LIKE', "%{$search}%")->simplepaginate(12);
return view('search', compact("data"));
}
Blade
#if(is_null(($data['books']) || ($data['authors'])))
<h2>Not Found, please try using another search term</h2><br/><br/>
#endif
#foreach($data['books'] as $book)
<a href="{{ route('book', $book->id) }}" target="_blank">
<img src="{{ secure_asset($book->image_url) }}" class="img-responsive" alt="{{$book->image_url}}">
</a>
<p class="author">{{ $book->author->name }}</p>
<h1 class="book-title">{{str_limit($book -> name, 20) }}</h1>
#endforeach
#forelse($data['authors'] as $author)
<a href="{{ route('author', $author->id) }}" target="_blank">
<img src="{{ secure_asset($author->image_url) }}" class="img-responsive" alt="{{$author->image_url}}">
</a>
<p class="author"></p>
<h1 class="book-title">{{str_limit($author -> name, 20) }}</h1>
#endforeach
What I am trying to is to say
Not Found, please try using another search term
When the search term can't be found. But this is not working for me
#if(is_null(($data['books']) || ($data['authors'])))
<h2>Not Found, please try using another search term</h2><br/><br/>
#endif
It doesn't return the Not found
That's because even with no resuts, the value of $data['books'] or $data['authors'] is not null, instead it's an empty collection. So you should check the count of results:
#if(!$data['books']->count() || !$data['authors']->count())
<h2>Not Found, please try using another search term</h2><br/><br/>
#endif
or use the isEmpty() method:
#if($data['books']->isEmpty() || $data['authors']->isEmpty())
<h2>Not Found, please try using another search term</h2><br/><br/>
#endif
also, it should actually be an AND insted of OR, IMO:
or use the isEmpty() method:
#if($data['books']->isEmpty() && $data['authors']->isEmpty())
<h2>Not Found, please try using another search term</h2><br/><br/>
#endif

in laravel error Invalid argument supplied for foreach() (View: i cant see $value

I am trying to make a blog foreach that see this erro
Invalid argument supplied for foreach() (View:
my site https://weadam.com/
my code is:
controller:
public function index()
{
$localetmp = Session::get('locale');
$blogs = #json_decode(file_get_contents("https://www.weadam.com/blogs/wp-json/wp/v2/posts?per_page=4&lang=" . $localetmp));
$blogsold = Blog::orderBy('id','desc')->take(100)->get();
foreach ((array)$blogs as $blog){
// $blog->elapsed = $this->time_elapsed_string('#'.$blog->date);
// $blog->date = date("d F Y",$blog->date);
}
$error = "";
return view('home-new',['blogs' => $blogs]);
}
and view is:
<div class="eng-home-blog">
<div class="col-sm-9 home-post-disp bx-shadow brd-radius bg-white">
#foreach($blogs as $blog)
#if($blog->sticky)
<img src="{{$blog->fimg_url}}" alt="" class="img-responsive brd-radius bx-shadow">
<div class="hm-post-date">{{$blog->date}}</div>
<h3>{{$blog->title->rendered}}</h3>
<p>{!!$blog->excerpt->rendered!!}</p>
<span>{{__("READ MORE")}}</span>
#endif
#endforeach
</div>
</div>
pass true as secondary param at json_decode function
$blogs = #json_decode(file_get_contents("https://www.weadam.com/blogs/wp-json/wp/v2/posts?per_page=4&lang=" . $localetmp),true);
now you have to fetch this blog data as associative data. not as an object. here's the example code for it
<div class="eng-home-blog">
<div class="col-sm-9 home-post-disp bx-shadow brd-radius bg-white">
#foreach($blogs as $blog)
#if($blog['sticky'])
<img src="{{$blog['fimg_url']}}" alt="" class="img-responsive brd-radius bx-shadow">
<div class="hm-post-date">{{$blog['date']}}</div>
#endif
#endforeach
</div>
</div>
You can simply use forelse it will take care of the empty case
#forelse($blogs as $blog)
// do what ever you want to do
#empty
<div> Nothing to show </div>
#endforelse
Hope it helps reference.
Thanks.

Ternary in Laravel Blade to apply row class names

I have this report that Im trying to do, but I want to make the rows alternate colors. this is what I tried, but it does not work. What is the correct way to achieve this?
<div class="row">
{{$rowOrder = "even"}}
#foreach($data as $row)
{{ $rowLine = ($rowOrder = "odd" ? 'even' : 'odd') }}
<div class="col-sm-4 repColumn {{$rowOrder}}">
<span>{{$row->adm_referraldate}}</span>
<span>{{$row->adm_number}}</span>
</div>
<div class="col-sm-4 repColumn {{$rowOrder}}">
<span>{{$row->dmg_nhsnumber}}</span>
<span>{{$row->dmg_firstname." ".$row->dmg_surname}}</span>
<span>{{$row->dmg_dateofbirth." - (".$row->dmg_ageyears.")"}}</span>
<span>{{$row->dmg_sex}}</span>
</div>
<div class="col-sm-4 repColumn {{$rowOrder}}">
<span>{{$row->dmg_nhsnumber}}</span>
<span>{{$row->dmg_firstname." ".$row->dmg_surname}}</span>
<span>{{$row->dmg_dateofbirth." - (".$row->dmg_ageyears.")"}}</span>
<span>{{$row->dmg_sex}}</span>
</div>
#endforeach
</div>
Replace
{{ $rowLine = ($rowOrder = "odd" ? 'even' : 'odd') }}
with
<?php $rowOrder = ($rowOrder == "odd") ? 'even' : 'odd'; ?>
or if you are using a Laravel 5.2 or up
#php($rowOrder = ($rowOrder == "odd") ? 'even' : 'odd')
Do the same for the line {{$rowOrder = "even"}}
If you used the {{$rowOrder = "even"}} it will echo out the result.
You can use modulo arithmetic to decide whether and index is odd or even:
$isEven = index % 2
If you combine this with a PHP ternary operator then you'd get this
{{ $loop->index % 2 ? 'odd': 'even' }}
see
https://davidwalsh.name/php-shorthand-if-else-ternary-operators
and
https://en.wikipedia.org/wiki/Modular_arithmetic
Here's a very easy solution:
#php $count = 0; #endphp
#foreach($data as $row)
<div class="{{ ++$count % 2 ? 'odd': 'even' }}">
{{ $row->name }}
</div>
#endforeach
Use variable $loop documentation ( $loop->even laravel 5.8, or ($loop->iteration % 2)laravel< 5.8 )
#foreach ($users as $user)
#if ($loop->even)
This is even.
#else
#endif
#endforeach
or
#foreach ($listObject as $Object)
<tr class="{{ ($loop->iteration % 2) ? 'odd' : 'even' }}">
#endforeach
{{ $rowLine = ($rowOrder = "odd" ? 'even' : 'odd') }}
possibly should be
{{ $rowLine = ($rowOrder == "odd" ? 'even' : 'odd') }}
Here's a working example for me: I left the dump output in it so you can see the actual number counting up. Hope it helps anyone who comes across this problem :). EDIT: Don't forget to add colors in your css file for .odd and .even!
#if(!empty($names))
{{-- SET VARIABLE + HIDE IT --}}
<div class="hide">{!! $number = 0 !!}</div>
#foreach($names as $n)
{{ dump($number) }}
<div class="{!! $number % 2 == 0 ? 'odd' : 'even' !!}">
{{-- UP VARIABLE + HIDE IT --}}
<div class="hide">{!! $number++ !!}}</div>
{{-- DISPLAY CONTENT —}}
{{ $n }}
</div>
#endforeach
#endif
Try getting the key from the foreach loop and run ($key % 2)
Basically Odd Number mod 2 always have a remainder
#foreach ($rows as $key => $row)
<div class="#if ($key > 0 && $key % 2) odd #else even #endif">
</div>
#endforeach

Recursive display of data with blade, laravel

My Controller:
class Comments extends Controller {
public function GenerateComments($id){
$theme = DB::table('New_Themes')
->where('id', $id)
->get();
$Comments = NewTheme_Comment::where('id_theme', $id)->get();
return view('comments', ['Themes'=>$theme, 'Comments'=>$Comments]);
}
My Table(NewTheme_Comment):
id
parent_id
id_theme
user
text
upVotes
downVotes
My view(contains the recursive display of the tree of comments like the same in reddit), ......(data) contains the bootstrap media object, and the </div>'s things are used to round up (visually) the tree of comments as it should be:
<?php
tree($Comments, 0, 0);
$var = -1;
function tree($Comments, $parent_id = 0, $level=0, $c=0) {
global $var;
foreach($Comments as $Comment) {
if($Comment['parent_id'] == $parent_id) {
If ($level > $var) $var++; else {
for ($i = $var-$level+1; $i>0; $i--) { if ($c < 0) echo '</div> </div>'; else $c--; };
$var=$level;
};
echo '........(data)';
tree($Comments, $Comment['id'], $level+1,$c);
};
};
};
?>
The problem is that .........(data) should contain this stuff:
<div class="media">
<div class="media-left">
<img class="media-object" style="height:40px; width:40px;" src="{{ URL::asset("images/upVote.svg") }}" >
<div>{{$Comment->upVotes-$Comment->downVotes}}</div>
<img class="media-object" style="height:40px; width:40px;" src="{{ URL::asset("images/downVote.svg") }}" >
</div>
<div class="media-body">
<p class="media-heading">{{ $Comment->text }}</p>
<p class="media-heading">{{ $Comment->user }} / {{ $Comment->created_at }} </p>
And I am using the blade above this line | , which I can't integrate into that echo in view, replacing the ..........(data).
I have the intuition that the function I should integrate into the controller but I am broken(I spent to much time on recursive method of displaying comments) and I don't know how to take the data and print out it as whole unit recursively.
Any help is GREATLY appreciated to find a way out of this mess, thank you very much
Edit 1:
This is an example if i am filling with bootstrap media object in ........(data):
<div class="media">
<a class="media-left" href="#">
<img class="media-object" src="..." alt="...">
</a>
<div class="media-body">
<h4 class="media-heading">Media heading</h4>
Without 2 x </div>
You are approaching the views in a wrong way, as blade templates are not meant to use functions, it's better to follow the below recommendations.
The best way for that is to place the function code inside a blade file, for example recursive.blade.php:
recursive.blade.php
#foreach($comments as $comment)
//place your code here
#endforeach
Then in your main blade you can call it several times:
main.blade.php
<div>
#include('recursive', ['comments' => $comments])
</div>
The below example works for me and is the most widely used approach. remember the default value for parent_id is -1.
Model
public function children(){
return $this->hasMany(self::class,'parent_id','id')->with('children');
}
Controller
$comments = Comments::where('parent_id','=',-1)->get();
return view('comments',['comments'=> $comments]);
Blade (comments.blade.php)
<div class="tree">
#include('comment-list-widget',['comments' => $comment])
</div>
Blade (comment-list-widget.blade.php)
<ul>
#foreach($comments as $comment)
<li>
<a>{{$comment->text}}</a>
#if(!empty($comment->children) && $comment->children->count())
#include('comment-list-widget',['comments' => $comment->children])
#endif
</li>
#endforeach
</ul>

Laravel dynamic breadcrumbs with links

I am trying to implement dynamic breadcrumbs in laravel with links. I successfully render the breadcrumbs but without links by following code.
<ol class="breadcrumb">
<li><i class="fa fa-dashboard"></i>Marketplace</li>
#foreach(Request::segments() as $segment)
<li>
{{$segment}}
</li>
#endforeach
</ol>
But now i am facing issue with the urls. I am getting the current url of the route with all the decendents. Can someone please help me that how can I add links to the breadcrumbs ?
Thanks.
If I understand your issue correctly, you just need to fill in the URL of the link. This is untested but I think it should work.
<ol class="breadcrumb">
<li><i class="fa fa-dashboard"></i>Marketplace</li>
<?php $segments = ''; ?>
#foreach(Request::segments() as $segment)
<?php $segments .= '/'.$segment; ?>
<li>
{{$segment}}
</li>
#endforeach
</ol>
This worked for me, tried in Laravel 5.4.*
Requirement for this code to work flawlessly: All URL's should have hierarchy pattern in your routes file
Below code will create crumb for each path -
Home >
<?php $link = "" ?>
#for($i = 1; $i <= count(Request::segments()); $i++)
#if($i < count(Request::segments()) & $i > 0)
<?php $link .= "/" . Request::segment($i); ?>
{{ ucwords(str_replace('-',' ',Request::segment($i)))}} >
#else {{ucwords(str_replace('-',' ',Request::segment($i)))}}
#endif
#endfor
So Breadcrumb for URL your_site.com/abc/lmn/xyz will be - Home > abc > lmn > xyz
Hope this helps!
Im not sure if you already got a solution for this, but i figured out a way to go about it on my project. It might come in handy for your implementation.
I ended up with either adding the whole url to the link or only the segment, which ofc is not desirable, so using array slice i start slicing from the 0 index in the array and only slice untill the current iteration of the loop, then implode the array into a string and then use URL::to to create the link.
<ol class="breadcrumb">
<li>
<i class="fa fa-home"></i>
HOME
</li>
#for($i = 2; $i <= count(Request::segments()); $i++)
<li>
<a href="{{ URL::to( implode( '/', array_slice(Request::segments(), 0 ,$i, true)))}}">
{{strtoupper(Request::segment($i))}}
</a>
</li>
#endfor
</ol>
As you will notice, I only start my iteration from 2 ($i = 2) as my app base url starts at /admin and i manually put my home Url in the first breadcrumb.
Again you might already have a solution, but throught this could work for people who do not want to add the package to get breadcrumbs.
I wrote a this code that can handle laravel resource ( index | edit | create ) routes dynamically:
Custom Breadcrumb => custom.blade.php
#php
$segments=[];
$l=count(Request::segments())-1
#endphp
#switch(Request::segments()[$l])
#case('edit')
#php
$l--;
$segments=array_slice(Request::segments(),0,$l);
$segments[]=$model->slug // Model that passed to this included blade file
#endphp
#break
#default
#php $segments=Request::segments() #endphp
#endswitch
#php
$link=''
#endphp
#foreach($segments as $sg)
#php $link.='/'.$sg #endphp
#if($loop->index<$l)
<li class="breadcrumb-item">
{{ucfirst($sg=='admin'?'home':$sg)}}
</li>
#else
<li class="breadcrumb-item active">
{{ucfirst($sg)}}
</li>
#endif
#endforeach
Use Custom Breadcrumb => example.balde.php
#include('admin.vendor.breadcrumb.custom',['model'=> $articles])
Just add slash / before any link to add decendents to domain name
like that
<a href="/YourLink" ></a>
I liked the solution offered by #rohankhude but it was not showing "/" after the first segment (marketplace). So here is a clean code.
<div class="breadcrumb">
<ul>
<li>
Home
</li>
<?php $link = "" ?>
#for($i = 1; $i <= count(Request::segments()); $i++)
#if($i < count(Request::segments()) & $i > 0)
<?php $link .= "/" . Request::segment($i); ?>
#if ($i == 1)
/ {{ ucwords(str_replace('-',' ',Request::segment($i)))}}
#else
{{ ucwords(str_replace('-',' ',Request::segment($i)))}}
#endif
#else
<a class="active">/ {{ucwords(str_replace('-',' ',Request::segment($i)))}}</a>
#endif
#endfor
</ul>
</div>

Resources