Undefined property: Illuminate\Database\Eloquent\Collection:: Laravel 5.2 - php

I'm trying to get iot to show The items within an order and i keep getting this error
These are my models
class westcoorder extends Model
{
protected $table = 'westcoorders';
protected $with = 'westcoorderitem';
protected $fillable = ['is_sent', 'is_delivered'];
/**
* #return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function westcoorderitem()
{
return $this->hasMany('App\westcoorderitem');
}
}
class westcoorderitem extends Model
{
protected $table = 'westcoorderitems';
protected $fillable = ['westcoorder_id','quantity', 'productName', 'productCode', 'price'];
public function westcoorder()
{
return $this->belongsTo('App\westcoorder');
}
}
This is my controller
public function onGoingOrder($orderNumber)
{
$orderNumber = westcoorder::where('id', $orderNumber)->firstOrFail();
$items = westcoorderitem::where('westcoorder_id', $orderNumber)->get();
return view('westco.onGoingOrder', compact('orderNumber', 'items'));
}
And this is what i have in my view
<div class="panel-heading">Order #if ($orderNumber) {{ $orderNumber->id }} #endif Items</div>
<div class="panel-body">
#if($items)
{{ $items->productName }}
#endif
</div>
Here is what my tables looks like
Schema::create('westcoorders', function (Blueprint $table)
{
$table->increments('id');
$table->tinyInteger('is_sent')->default(0);
$table->tinyInteger('is_delivered')->default(0);
$table->timestamps();
} );
Schema::create('westcoorderitems', function (Blueprint $table)
{
$table->increments('id');
$table->Integer('westcoorder_id'); // fk for westcoOrder.id
$table->string('quantity');
$table->string('productName');
$table->string('productCode');
$table->decimal('price');
$table->timestamps();
} );
And this is the error that I'm getting
Undefined property: Illuminate\Database\Eloquent\Collection::$productName

Like your error states:
Undefined property: Illuminate\Database\Eloquent\Collection::$productName
You are trying to access a property on a Collection, instead of a Model.
First, you can make use of the relationship you created, like so:
$order = App\westcoorder::where('id', $orderNumber)->with('westcoorderitem')->firstOrFail();
This will ensure the order items will be included with the result, instead of executing another query to fetch them.
You can then pass on the $order to the view:
return view('welcome', compact('orderNumber', 'order'));
(You can probably just leave out the orderNumber which was the actual order, as well)
Then you can access the order in your view and loop through the items like this:
#foreach($order->westcoorderitem as $item)
{{ $item->productName }}
#endforeach
FK
Another tip could be to update your table to use indexes to improve performance and make it neat, like the FK you mention in the comment of your create migration. You can make a migration to update it, like:
$table->foreign('westcoorder_id')->references('id')->on('westcoorders');
And/or expand on this, according to your needs (cascading, etc).

Related

Attempt to read property on int

My relations:
Content mode =>
class Content extends Model
{
use HasFactory;
protected $table = "contents";
protected $fillable = [ "body", "camapaign_id" ];
public function campaigns(){
return $this->belongsTo(Campaign::class, "campaign_id");
}
}
My camapaign model =>
class Campaign extends Model
{
use HasFactory;
protected $table = "campaigns";
protected $fillable = [ "ringba_campaign_id", "is_active" ];
public function contents(){
return $this->hasMany(Content::class, "content_id");
}
}
Here are my migrations:
content table =>
public function up()
{
Schema::create('contents', function (Blueprint $table) {
$table->id();
$table->timestamps();
$table->string("body", 255);
$table->foreignIdFor(\App\Models\Campaign::class)->nullable();
});
}
Campaign table =>
public function up()
{
Schema::create('campaigns', function (Blueprint $table) {
$table->id();
$table->timestamps();
$table->string("ringba_campaign_id", 255);
$table->boolean("is_active")->default(0);
});
}
Here is my content controller:
public function index(){
$contents = Content::all()->sortBy("created_at");
return view("Dashboard.Contents.contents", [
"contents" => $contents
]);
}
I am trying to access ringba_camapaign_id in here like this =>
#foreach($contents as $content)
{{ $content->campaign_id->ringba_campaign_id }}
#endforeach
But I am getting this error : Attempt to read property on int
A couple of things here, since Content BelongsTo a Campaign the method should be singular.
public function campaign(): BelongsTo
{
return $this->belongsTo(Campaign::class, 'campaign_id');
}
Then when you do $content->campaign_id you are getting the property on the model and so is returning an int. What you want to do is return the campaign model like so $content->campaign through the relationship defined in the Content model. Now you can access the property on the campaign model, $content->campaign->ringba_campaign_id.
However it also looks like a campaign can be nullable by your migration so you would need to add protection from this so you don't get property on null errors. So this would look like optional($content->campaign)->ringba_campaign_id, this would then return null if the Content didn't have a Campaign.
Actually I wrote bad relation code inside content model:
Before I wrote:
public function campaigns(){
return $this->belongsTo(Campaign::class);
}
Answer will be :
public function campaign(){
return $this->belongsTo(Campaign::class);
}
I wrote campaigns instead of campaign.
try this.
#foreach($contents as $content)
{{ $content->campaigns->ringba_campaign_id }}
#endforeach
for more information check this link

BadMethodCallException: Method does not exist

I am trying to create a many to many relationship between this profile and an availability table but within my test i keep getting call to a undefined method on availability in the test.
This is the controller function
/**
* Creates association between availability and podcast profile
*
* #param array $availabilities
*/
private function associateAvailability(array $availabilities)
{
$this->podcastProfile->availability()->sync(
array_map(function ($availability) {
$availabilityModel = Availability::where('availability', '=', $availability)->first();
return $availabilityModel->id;
}, $availabilities)
);
}
This is the method in the podcast profile model
/**
* Defines many-to-many relationship between podcasts and availabilities
*/
public function availability(): BelongsToMany
{
return $this->belongsToMany(
'App\Models\Availability',
'podcast_availability',
'podcast_profile_id',
'availability_id'
);
}
This is the test for the method
/**
* #test
*/
public function it_should_create_availability_relationship()
{
$this->handlePostRequestToController();
$this->assertTrue($this->user->podcastProfile->availability()->exists());
$this->checkAvailability($this->requestData['availability']);
}
this is the check availability method inserted into the test
/**
* Check database
*
* #param $availabilities
*/
private function checkAvailability($availabilities): void
{
foreach ($availabilities as $availability) {
$availabilityModel = Availability::where('availability', '=', $availability)
->first();
$this->assertDatabaseHas('podcast_availability', [
'podcast_profile_id' => $this->user->podcastProfile->id,
'availability_id' => $availabilityModel->id
]);
}
}
this is the error
1) Tests\Feature\PodcastProfileControllerTest::it_should_create_availability_relationship
BadMethodCallException: Method Illuminate\Database\Eloquent\Collection::availability does not exist.
If your trying to make a Many to Many relationship base on Laravel Many to Many Relationship.
Here's how you do it. You need to have to 2 models and 3 migrations.
FIRST
Your model should look like this:
Profile Model
protected $guarded = [];
public function availabilities() {
return $this->belongsToMany(Availability::class);
}
Note: I use availabilities because it is in a many to many relationship so its a better naming convention.
Availability Model
protected $guarded = [];
public function profiles() {
return $this->belongsToMany(Profile::class);
}
SECOND
Your migration should be like this:
Profile Migration
Schema::create('profiles', function (Blueprint $table) {
$table->bigIncrements('id');
...
$table->timestamps();
});
Availability Migration
Schema::create('availabilities', function (Blueprint $table) {
$table->bigIncrements('id');
...
$table->timestamps();
});
Availability And Profiles Migration
Schema::create('availability_profile', function (Blueprint $table) {
$table->bigIncrements('id');
$table->unsignedBigInteger('availability_id');
$table->unsignedBigInteger('profile_id');
$table->timestamps();
});
Note: I use the availability_profile naming convention in alphabetical order
INFO
You can generate this migration using artisan command like this php artisan make:migration create_availability_profile_table --create=availability_profile
LAST
In you controller you can assign the profile to availability
Controller
Assuming you have record on your database.
public function generateAvailability() {
$profile = Profile::firstOrFail(1);
$role = Role::firstOrFail(1);
$profile->availabilities()->attach($role->id);
dd(profile->availabilities);
}
Note: I use dd(dump and die) to check the record
You can also see this reference and this

Laravel : Join two tables get the info from table one and get the first related image from table two

I have two table one is propertyDetails and the other is propertyImages
and I have done the relation between the two tables like so..
here is the models
propertyDetails
class PropertyDetail extends \Eloquent {
protected $fillable = [];
public function propImages()
{
return $this->hasMany('PropertyImage', 'property_details_id');
}
}
Table migration
public function up()
{
Schema::create('property_details', function (Blueprint $table) {
$table->increments('id');
$table->enum('purpose', array('Sell', 'Rent'));
$table->integer('property_owner_id')->unsigned();
$table->integer('property_agent_id')->nullable();
$table->integer('bedroom');
$table->integer('dining_room');
$table->integer('bathroom');
$table->string('title', 100);
$table->integer('price');
$table->string('type', 120);
$table->string('specify_type', 120);
$table->text('details');
$table->integer('active');
$table->foreign('property_owner_id')->references('id')->on('property_owners')->onDelete('cascade');
$table->timestamps();
});
}
propertyImages
class PropertyImage extends \Eloquent
{
protected $fillable = [];
public function propertyImages()
{
return $this->belongsTo('PropertyDetail', 'property_details_id');
}
}
Table migration
Schema::create('property_images', function(Blueprint $table)
{
$table->increments('id');
$table->integer('property_details_id')->unsigned();
$table->foreign('property_details_id')->references('id')->on('property_details')->onDelete('cascade');
$table->binary('image');
$table->timestamps();
});
}
what I want to do is select all the projectsDetails with the first related image from table two propertyImages
I tried
$properties = PropertyDetail::with('propImages')->get();
return View::make('admin.properties.view', compact('properties'));
and in my view
#foreach($properties as $property)
{{ HTML::image('images/propertyImages/'.$property->propImages->image, $property->title, array('width'=>767, 'height'=>384)) }}
#endforeach
got
Undefined property: Illuminate\Database\Eloquent\Collection::$image
As the error says, you're trying to get a relationship on a collection, the relationship exists on the objects (records) in that collection. You need to loop over the Properties, and for each one get their items...
#foreach ($properties as $property)
// access property properties here
#foreach ($property->image as $image)
// access image properties here.
#endforeach
#endforeach
Change this line:
return View::make('admin.properties.view', compact('properties'));
to
return View::make('admin.properties.view', ['properties' => $properties]));
and try again.
Note: The second argument passed to View::make is an array of data that should be made available to the view.
Reference
Thanks for all here is how I got it to work
in the view section as #Ferran suggested I did this
#foreach ($properties as $property)
// access property properties here
#foreach ($property->image as $image)
// access image properties here.
#endforeach
#endforeach
but because I need only the first image and not all I found the solution here
I just changed the second #foreach to use slice
here is the final code
#foreach ($properties as $property)
// access property properties here
#foreach($property->propImages->slice(0, 1) as $image)
// access image properties here.
#endforeach
#endforeach

Trying to get property of non-object on one to many relationship

So, i'm trying to learn laravel and i kind of got stuck on one to many relationship. So, i have a page with 3 links on it, and logging into the db the click on those links. All good, i click on link, it registers in the db the id of the link but when i try to print them in the view i get "Trying to get property of non-object".
My models:
class NiceAction extends Model
{
public function logs(){
return $this->hasMany('App\NiceActionLog');
}
}
class NiceActionLog extends Model
{
public function log(){
return $this->belongsTo('App\NiceAction');
}
}
My controller:
This is how i log into the db on click:
public function getNiceAction($action, $name = null){
if ($name == null) {
$name = 'you';
}
$nice_action = NiceAction::where('name', $action)->first();
$nice_action_log = new NiceActionLog();
$nice_action->logs()->save($nice_action_log);
return view('actions.nice', ['action' => $action, 'name' => $name]);
}
And this is how i pass the loggs to the view:
public function getHome(){
$actions = NiceAction::all();
$logged_actions = NiceActionLog::all();
return view('home', ['actions' => $actions, 'logged_actions' => $logged_actions]);
}
And this is in my view:
#foreach($logged_actions as $loggedAction)
<li>{{ $loggedAction->log->name}}</li>
#endforeach
LATER EDIT:
My tabels looks like this if this could be the problem:
nice_action_logs table:
public function up()
{
Schema::create('nice_action_logs', function (Blueprint $table) {
$table->increments('id');
$table->timestamps();
$table->integer('nice_action_id');
});
}
nice_actions table:
public function up()
{
Schema::create('nice_actions', function (Blueprint $table) {
$table->increments('id');
$table->timestamps();
$table->string('name');
$table->integer('niceness');
});
}
Your getHome() method has the following line:
$logged_actions = NiceAction::all();
I'm assuming this is actually meant to be:
$logged_actions = NiceActionLog::all();
Since you're still getting the error after correcting this, you probably have a NiceActionLog record that does not have an associated NiceAction record. Because of this, $loggedAction->log will be null, and then $loggedAction->log->name will give you the error you're seeing.
You can check to see if log exists before attempting to access a property on it:
#foreach($logged_actions as $loggedAction)
<li>{{ $loggedAction->log ? $loggedAction->log->name : 'No Log' }}</li>
#endforeach
Based on your update with the table definitions, your belongsTo relationship is not defined correctly. The belongsTo side of the relationship builds the foreign key name based on the name of the relationship method. You've named your relationship method log(), so it will look for a field on the nice_actions_logs table named log_id. You either need to rename your relationship method to match the foreign key field, or you need to pass the foreign key field to use in as the second parameter.
class NiceActionLog extends Model
{
// change the relationship method so the foreign key name will be correct
public function nice_action() {
return $this->belongsTo('App\NiceAction');
}
}
Or
class NiceActionLog extends Model
{
// leave relationship method alone, but supply the foreign key to the relationship
public function log() {
return $this->belongsTo('App\NiceAction', 'nice_action_id');
}
}
The hasMany side of the relationship builds the foreign key name based on the class name, so since your class is named NiceAction, it will look for the nice_action_id field, which is correct. There is no need to change this relationship definition or name.
Try this code to view what $loggedAction really contains:
#foreach($logged_actions as $loggedAction)
<li>{{ var_dump($loggedAction)}}</li>
#endforeach
Then, look at the output, and see what's wrong.
Possible answers:
$loggedAction->log might be null
$loggedAction might be an array (not so possible)
You can check the logs variable before putting like this:
#foreach($logged_actions as $loggedAction)
<li>
#if (property_exists($loggedAction->log,"name"))
{{$loggedAction->log->name}}
#else
No Log
#endif
</li>
#endforeach
Ok i've got it. I've changed my models into these and now works:
class NiceAction extends Model
{
public function NiceAction(){ //changed function's name
return $this->hasMany('App\NiceActionLog');
}
}
class NiceActionLog extends Model
{
public function NiceActionLog(){ // changed function's name
return $this->belongsTo('App\NiceAction', 'nice_action_id'); // added nice_action_id parameter
}
}

Laravel Eloquent one-to-one relationship setup

I am setting up a one to one relationship in a laravel application, but I am getting the error "trying to get property of non-object" when I try to reference a related table.
My Contractor.php model:
class Contractor extends Eloquent {
/**
* The database table used by the model.
*
* #var string
*/
protected $table = 'contractor';
function profile() {
return $this->hasOne('ContractorProfile');
}
}
My ContractorProfile.php model:
<?php
use Illuminate\Auth\UserInterface;
use Illuminate\Auth\Reminders\RemindableInterface;
class ContractorProfile extends Eloquent {
/**
* The database table used by the model.
*
* #var string
*/
protected $table = 'contractor_profile';
public function contractor() {
return $this->belongsTo('Contractor');
}
}
here is the snippet of my view file
show.blade.php
<div>
<h4>{{ $contractor->profile->tag_line }}</h4></p>
</div>
If I just call $contractor->profile the page loads but nothing is echoed back. If I add the ->tag_line, I get the "trying to get property of non-object" error. tag_line is a column name inside of my contractor_profile table.
Do you see an error that I am making?
TIA
EDIT: Database info:
Schema::create('contractor', function ($table) {
$table->increments('id');
$table->integer('hba_number')->nullable();
$table->integer('msn')->nullable();
$table->string('type')->default("");
$table->string('name')->default("");
$table->string('address_1')->default("");
$table->string('address_2')->default("");
$table->string('city')->default("");
$table->string('state')->default("");
$table->string('zip')->default("");
$table->string('country')->default("");
$table->string('phone')->default("");
$table->string('website')->default("");
$table->integer('company_id')->nullable();
$table->integer('user_id');
$table->timestamps();
$table->softDeletes();
});
Schema::create('contractor_profile', function ($table) {
$table->increments('id');
$table->integer('contractor_id');
$table->string('tag_line')->default("");
$table->string('story')->default("");
$table->string('area_of_operation')->default("");
$table->text('experience')->default("");
$table->text('education')->default("");
$table->text('insurance_verified')->default("");
$table->timestamps();
$table->softDeletes();
});
The issue may be because you're using a non-standard table name for your Contractor model. Try defining the relationship in your ContractorProfile model by specifying the second parameter to belongsTo:
return $this->belongsTo('Contractor', 'contractor_id');
You may also need to perform the same mapping on the Contractor model as well:
return $this->hasOne('ContractorProfile', 'contractor_id');

Categories