Unable to display image from database - Laravel - php

I have a relationship with product and images. The user can upload many images for a product so I have a product table and product_images table.
When I try to get to fetch the image from the database, I get No image available in my view. But I am able to save to the path attribute in my database.
Why could this be happening?
product_images
id
product_id
path
Product
public function images()
{
return $this->hasMany(Image::class);
}
Image
public function products()
{
return $this->belongsTo(Product::class);
}
Controller
public function index()
{
$products = Product::where('type', 'BASIC')->inRandomOrder()->take(6)->get();
return view('home.index',compact('products');
}
$product_image = Product::create($request->all());
if ($request->hasFile('image'))
{
$request->file('image')->store('uploads/catalog/images');
// ensure every image has a different name
$file_name = $request->file('image')->hashName();
// save new image $file_name to database
$product_image->images()->update(['image' => $file_name]);
}
View
#foreach($products as $product)
#foreach($product->image as $img)
<div class="product-item men">
<div class="product discount product_filter">
<div class="product_image">
<img src="{{$img}}" alt="">
</div>
<!-- <div class="favorite favorite_left"></div> -->
<!-- <div class="product_bubble product_bubble_right product_bubble_red d-flex flex-column align-items-center"><span>offer</span></div> -->
<div class="product_info">
<h6 class="product_name">{{$product->name}}</h6>
</div>
</div>
</div>
#endforeach
#endforeach
dd($img)
ProductImage {#523 ▼
#fillable: array:3 [▼
0 => "product_id"
1 => "path"
2 => "is_main_image"
]
#connection: "mysql"
#table: null
#primaryKey: "id"
#keyType: "int"
+incrementing: true
#with: []
#withCount: []
#perPage: 15
+exists: true
+wasRecentlyCreated: false
#attributes: array:6 [▼
"id" => 1
"product_id" => 1
"path" => "/Users/emmnock/laravel-ecommerce/public/uploads/catalog/ZsT4VwjWS5tLvIl0AKV6sAOxHFrwzwII5FMVUVkP.png"
"is_main_image" => null
"created_at" => "2018-03-07 10:04:34"
"updated_at" => "2018-03-07 10:04:34"
]
#original: array:6 [▶]
#changes: []
#casts: []
#dates: []
#dateFormat: null
#appends: []
#dispatchesEvents: []
#observables: []
#relations: []
#touches: []
+timestamps: true
#hidden: []
#visible: []
#guarded: array:1 [▶]
}

if your image is in public folder then use asset()
Here is an example
<img src="{{ asset(str_replace(app_path(),'',$img->path))}}" alt="">
also in your foreach
use below given code
#foreach($product->images as $img)
If it is storage folder then move the image to storage then use asset() or create a symlink
use asset(str_replace(app_path(),'',$img->path))
Hope this helps

You can't use img object to echo it. Image must have some properties like url or path, so you can output them only. Looks like you store full path (why?) inside path property.
$url = str_replace(public_path(), "", $img->path);
<img src="{{ $url }}" alt="">
If you store filename as an image property, so get url to it.
<img src="{{ Storage::url($img->path_to_file) }}" alt="">

Your problem is with how you store the image in the database.
$request->file('image')->store('uploads/catalog/images');
// ensure every image has a different name
$file_name = $request->file('image')->hashName();
// save new image $file_name to database
$product_image->images()->update(['image' => $file_name]);
You are using store() to save the file, then you are generating a new file name using hashName() and that is no way related to the image file that has been stored in 'uploads/catalog/images'.
The proper way would be to get the full path of the image stored returned by the store() method, and save that in the database.
$image_path = $request->file('image')->store('uploads/catalog/images');
$product_image->images()->update(['image' => $image_path]);

Related

calling a controller when pressing button

I am trying to add a new button which is for returning a used card. I am not sure why the data is not being sent with the request.
here is my index.blade.php
<form action="{{ route('assignees.destroy',$assignee->id) }}" method="POST">
<a class="btn btn-info" href="{{ route('assignees.show',$assignee->id) }}">Show</a>
<a class="btn btn-primary" href="{{ route('assignees.edit',$assignee->id) }}">Edit</a>
<a class="btn btn-info" href="{{ route('returncard',$assignee->id) }}">Return Card</a>
#csrf
#method('DELETE')
<button type="submit" class="btn btn-danger">Delete</button>
</form>
and here is my controller where I am defining the return card route:
public function returncard(assignee $assignee)
{
//
$assignee->timeout = now();
$assignee->update();
return redirect()->route('assignees.index')
->with('success','assignee updated successfully');
}
web.php:
Route::resource('assignees','AssigneeController');
Route::get('autocomplete', 'AssigneeController#autocomplete')->name('autocomplete');
Route::get('searchcard', 'AssigneeController#searchcard')->name('searchcard');
Route::get('returncard', 'AssigneeController#returncard')->name('returncard');
output of dd($assignee)
Assignee {#266 ▼
#fillable: array:9 [▼
0 => "cabinet"
1 => "custidno"
2 => "timein"
3 => "timeout"
4 => "refnumber"
5 => "cardno"
6 => "refnumber"
7 => "entrytype"
8 => "notes"
]
#connection: null
#table: null
#primaryKey: "id"
#keyType: "int"
+incrementing: true
#with: []
#withCount: []
#perPage: 15
+exists: false
+wasRecentlyCreated: false
#attributes: []
#original: []
#changes: []
#casts: []
#dates: []
#dateFormat: null
#appends: []
#dispatchesEvents: []
#observables: []
#relations: []
#touches: []
+timestamps: true
#hidden: []
#visible: []
#guarded: array:1 [▶]
}
when pressing any button nothing is happening and the timeout is not being updated.
You need add a parameter in your route if you're trying to pass the assignee ID to the controller method:
Route::get('returncard/{assignee}', 'AssigneeController#returncard')->name('returncard');
The resource routes handle this for you, the specific routes (GET,POST,etc) do not. If you're using Route Model Binding, you need to make sure this parameter matches the argument name of your method.
I suggest you read the Laravel docs and follow the outlined naming conventions if you're working in the framework as Indra suggested in the comments.
Route::get('assignees/autocomplete/{assignees}', 'AssigneeController#autocomplete')->name('autocomplete');
Route::get('assignees/searchcard/{assignees}', 'AssigneeController#searchcard')->name('searchcard');
Route::get('assignees/returncard/{assignees}', 'AssigneeController#returncard')->name('returncard');
Route::resource('assignees','AssigneeController');
Change the routes like that then it will be working.
if you are creating own function in resource then you must to use route of that function before the resource route

Return view doesn't take variable in Laravel 5.4

Maybe is silly question but I have this in my Controller which is showing the form for image upload and after form is submitted should return me to another view.
On this another view I have passing variable with all images but still I've got
Undefined variable: images
So this is what I have in my Controller
// Display all Images
public function images()
{
$images = Images::paginate(3);
return view('images', compact('images'));
}
// Display image upload form
public function imageCreate()
{
return view('create');
}
// Submit and store image
public function imageStore( Request $request )
{
$image = new Images([
'caption' => $request['caption'],
'name' => $request['caption'],
'path' => 'uploads/noimage.png',
'hits' => 1,
'added_on' => '2017-08-08 9:00:00'
]);
$image->save();
return view('images', compact('images'));
}
And this in my view images.blade.php
#foreach($images as $image)
<img class="thumbnail block" src="{{ '../'.$image->path }}">
#endforeach
So, why variable is undefined if I posting it in the return view statement?
Update: dd($image) in the view return
Images {#234 ▼
#primaryKey: "id"
#table: "images"
+timestamps: false
+fillable: array:6 [▶]
#connection: null
#keyType: "int"
+incrementing: true
#with: []
#withCount: []
#perPage: 15
+exists: true
+wasRecentlyCreated: true
#attributes: array:7 [▼
"caption" => "dasdsadsad"
"name" => "dasdsadsad"
"path" => "uploads/noimage.png"
"hits" => 1
"added_on" => "2017-08-08 9:00:00"
"slug" => "dasdsadsad-7"
"id" => 144
]
#original: array:7 [▶]
#casts: []
#dates: []
#dateFormat: null
#appends: []
#events: []
#observables: []
#relations: []
#touches: []
#hidden: []
#visible: []
#guarded: array:1 [▶]
}
Update 2: routes
Route::get('images', 'HomeController#images');
Route::get('create',['as'=>'create','uses'=>'HomeController#imageCreate']);
Route::post('create',['as'=>'store','uses'=>'HomeController#imageStore']);
The issue is here:
compact('images'));
but your variable is $image. So change it to:
compact('image'));
and try again. And also change the foreach() variable name like:
#foreach($image as $img)
...
$img->slug
$img->path
Explanation:
The variable that contains the data is $image and the one you are passing from controller is compact('images')). An extra s is there.
passing-data-from-controller-to-views
error int this line
return view('images', compact('images'));
your variable name is $image and you pass $images
replace above line with this
return view('images', compact('image'));
public function imageStore( Request $request )
{
$image = new Images([
'caption' => $request['caption'],
'name' => $request['caption'],
'path' => 'uploads/noimage.png',
'hits' => 1,
'added_on' => '2017-08-08 9:00:00'
]);
$imagePath='uploads/noimage.png';
$image->save();
return view('images')->with('image',$imagePath);
}
you get path like this
<a href="{{ URL::to('image/'.$image->slug) }}">
<img class="thumbnail block" src="{{url('/'.$image)}}">
</a>
Laravel assumes when you use the compact function that the variable you are passing is named the same as the variable you are passing in the route. For instance:
route::get('/customer/{customer_id}', 'CustomerController#show');
Therefore in your controller when returning data with your view you need to do something like:
return view('customer', ['customer_name' => $customer->name]);
Then you should be able to reference it in your view like:
{{$customer_name}}

Laravel morphTo Returns Null

I am using Laravel 5.4 and having trouble figuring out why my morphTo relationship always returns null no matter what I do. The inverse of the relationship is fine, but when I try to retrieve the owner of the polymorphic relation, it is null.
class Opportunity extends Model {
public function Organization() {
return $this->morphTo('Organization');
}
}
class Account extends model {
public function Opportunities() {
return $this->morphMany('App\Opportunity', 'Organization');
}
}
class Department extends model {
public function Opportunities() {
return $this->morphMany('App\Opportunity', 'Organization');
}
}
$org = App\Opportunity::findOrFail(1)->Organization;
The full namespace is stored in the database and the _type and _id actually have the appropriate organization type and id in the columns (i.e., 'App\Account' and '456'). So, I know the database record and the returned Opportunity object have the correct Organization in the columns (I can see it in the database correctly), but no matter what I do, if I try to retrieve Organization it is null.
Here is the output. You will notice the Organization is in the attributes, but the relation is null and I cannot get it to return even adding ->with('Organization') to the query. It doesn't even seem to be executing the query to get the owner
#primaryKey: "ID"
+timestamps: true
#guarded: []
#hidden: []
#visible: []
#with: []
#dissociateRelations: []
#connection: null
#keyType: "int"
+incrementing: true
#perPage: 15
+exists: true
+wasRecentlyCreated: true
#attributes: array:13 [
"StageID" => 12
"TypeID" => 1
"OriginID" => 20
"Description" => "Interested in scanner fi6140"
"UserID" => 3
"SolutionValue" => ".00"
"MarginValue" => ".00"
"created_at" => "2010-09-16 11:19:00.000"
"updated_at" => "2015-09-01 12:32:00.000"
"_migrationID" => "4299"
"Organization_type" => "App\Account"
"Organization_id" => 456
"ID" => 1
]
#original: array:13 [
"StageID" => 12
"TypeID" => 1
"OriginID" => 20
"Description" => "Interested in scanner fi6140"
"UserID" => 3
"SolutionValue" => ".00"
"MarginValue" => ".00"
"created_at" => "2010-09-16 11:19:00.000"
"updated_at" => "2015-09-01 12:32:00.000"
"_migrationID" => "4299"
"Organization_type" => "App\Account"
"Organization_id" => 456
"ID" => 1
]
#dateFormat: null
#events: []
#observables: []
#relations: array:3 [
"Organization" => null
"Projects" => Illuminate\Database\Eloquent\Collection {#3463
#items: []
}
"Tickets" => Illuminate\Database\Eloquent\Collection {#3443
#items: []
}
]
#touches: []
#forceDeleting: false
change your morphto to this base on document to prevent confusing laravel to detect column type and column id
class Image extends Model
{
protected $fillable = [
"link",
"imageable_id",
"imageable_type",
];
public function imagable()
{
return $this->morphTo(__FUNCTION__, 'imageable_type', 'imageable_id');
}
}
So, it looks like I may have discovered my problem, but I do not know why. When the owner is queried by
App\Opportunity::findOrFail(1)->Organization
it looks like Eloquent is looking for organization_type and organization_id (with lowercase) and not Organization_type and _id. However, my migration uses $table->morphs('Organization') and so the columns in the database are created with the uppercase. When I change that to lowercase in the database, my results get returned. Not sure how to change that behavior though, and it seems to have been introduced after upgrading from 5.2
Edit: there was a change introduced in 5.3 that snake cases the _type and _id that seems to be the root cause of my experience
https://github.com/laravel/framework/pull/15334
After losing two half-days exploring all the solutions found on the net, I emptied the cache and everything works ...
php artisan cache:clear

Laravel Method Injection - Variable exists?

Let's say that we have Laravel's default User.php model, and we also have UsersController.php. Here's how the create method looks like:
public function create(User $user)
{
return view('backend.users.form', compact('user'));
}
As you can see - User $user is passed as argument, and view backend.users.form receives that $user.
If I add dd($user); in the create method:
public function create(User $user)
{
dd($user);
return view('backend.users.form', compact('user'));
}
the result will be:
User {#193 ▼
#fillable: array:3 [▼
0 => "name"
1 => "email"
2 => "password"
]
#hidden: array:2 [▼
0 => "password"
1 => "remember_token"
]
#connection: null
#table: null
#primaryKey: "id"
#perPage: 15
+incrementing: true
+timestamps: true
#attributes: []
#original: []
#relations: []
#visible: []
#appends: []
#guarded: array:1 [▶]
#dates: []
#dateFormat: null
#casts: []
#touches: []
#observables: []
#with: []
#morphClass: null
+exists: false
+wasRecentlyCreated: false
}
So, variable (instance) $user exists, right?
But, in a view backend.users.form that receives $user, if we do something like this:
<h3>{!! $user->exists ? 'Editing '.$user->name : 'Create New User' !!}</h3>
The result will be as if $user does not exist? The result will be Create New User. I do not understand it.
Can you explain to me why $user->exists returns false when dd($user); shows that it exists?
Without knowing your DI-container configuration, the User instance you inject probably does not exist as a record in the database - it has no identity. It is merely a model instance you can use.
Can you explain to me why $user->exists returns false when dd($user);
shows that it exists?
Please look carefully at the result of dd() inside a controller:
...
+exists: false
...
$user->exists is false here, so it will return false in any case.

Laravel htmlentities() expects parameter 1 to be string, array given

I'm trying to use https://github.com/skmetaly/laravel-twitch-restful-api package to get twitch integration to my website.
That's the error that i get.
ErrorException in helpers.php line 469:
htmlentities() expects parameter 1 to be string, array given (View: /var/www/rafdev.ovh/html/msvixen/resources/views/twitch.blade.php)
My controller
$code = Input::get('code');
if ($code !== null)
{
$token = TwitchApi::requestToken($code);
} else
{
$token = null;
}
$data = TwitchApi::streamsFollowed($token);
return view('twitch', ['token' => $token, 'data' => $data]);
my view
#extends('master')
#section('content')
<h1>Twitch.TV</h1>
{{ $token }}
{{ $data }}
#endsection
After using dd()
array:9 [▼
0 => array:11 [▼
"_id" => 17733016640
"game" => "World of Warcraft"
"viewers" => 15551
"created_at" => "2015-11-15T22:27:13Z"
"video_height" => 1080
"average_fps" => 60.2769481401
"delay" => 0
"is_playlist" => false
"_links" => array:1 [▶]
"preview" => array:4 [▶]
"channel" => array:22 [▶]
]
1 => array:11 [▶]
2 => array:11 [▶]
3 => array:11 [▶]
4 => array:11 [▶]
5 => array:11 [▶]
6 => array:11 [▶]
7 => array:11 [▶]
8 => array:11 [▶]
]
so it works, but when i try to display data - its back to the htmlentities() error
This is happening because $data is returned as an array.
When TwitchApi::streamsFollowed($token); is called, the Facade calls the method in Skmetaly\TwitchApi\Services\TwitchApiService.
This in turn creates an instance of Skmetaly\TwitchApi\API\Users and calls the streamsFollowed() method there.
This method makes a call to /streams/followed which returns a data set such as the example below. It's automatically converted to an array rather than JSON using the Guzzle HTTP Client's json() method.
{
"_links": {
"self": "https://api.twitch.tv/kraken/streams/followed?limit=25&offset=0",
"next": "https://api.twitch.tv/kraken/streams/followed?limit=25&offset=25"
},
"_total": 123,
"streams": [...]
}
In order to display the streams you'd need to iterate over the streams array within $data.
If you were to modify your controller slightly
return view('twitch', ['token' => $token, 'streams' => $data->streams]);
You'd then be able to iterate over the streams in your view.
#foreach($streams as $stream)
{{ $stream }}
#endforeach
Update: You'll notice that each stream is also an array. What this means is you need to choose which of the keys in each array you'd like to display. Let's assume that inside one of the streams there is a key called broadcaster which contains a string; you could modify the above as follows.
#foreach($streams as $stream)
{{ $stream['broadcaster'] }}
#endforeach
Having now read the streams example response documentation it would appear that the contents of a stream varies depending on whether or not the stream is online. NB: This is assuming the data structure is the same as you've not posted the contents of a stream in your question.
This means that offline, {{ $stream['broadcaster'] }} would work, but when online it wouldn't and you'd get the same error. What you'll likely need to do is use an #if #else block in your #foreach to determine if the stream is null before trying to echo part of the information.
You could also filter the offline streams in the controller by removing null values from data.

Categories