Laravel: Getting data from my pivot table - php

I've just started using Laravel and I am really enjoying it. I am a little confused about how to access data at times and i'm not sure if I am going around this in the right way, Maybe somebody can help?
I want to simply output the Club Name and Opponent Club Name in a loop of Fixtures.
I have the following tables:
// a clubs table
Schema::create('clubs', function($table) {
$table->increments('id');
$table->string('name', 20);
$table->string('code', 40);
$table->string('location', 20);
$table->string('colour', 20);
$table->string('alias', 20);
$table->string('image', 200);
$table->timestamps();
});
// a fixtures table
Schema::create('fixtures', function($table) {
$table->increments('id');
$table->string('type', 20)->nullable();
$table->string('date', 20)->nullable();
$table->string('time', 20)->nullable();
$table->string('venue', 20)->nullable();
$table->string('address', 20)->nullable();
$table->boolean('reminders')->nullable();
$table->timestamps();
});
// a pivot table
Schema::create('clubs_fixtures', function($table) {
$table->increments('id');
$table->integer('club_id')->unsigned(); // this is meant to be used as a foreign key
$table->foreign('club_id')->references('id')->on('clubs')->onDelete('cascade')->onUpdate('cascade');
$table->integer('opponent_id')->unsigned(); // this is meant to be used as a foreign key
$table->foreign('opponent_id')->references('id')->on('clubs')->onDelete('cascade')->onUpdate('cascade');
$table->integer('fixture_id')->unsigned(); // this is meant to be used as a foreign key
$table->foreign('fixture_id')->references('id')->on('fixtures')->onDelete('cascade')->onUpdate('cascade');
$table->timestamps();
});
So a CLUB can have MANY FIXTURES and a FIXTURE can have MANY CLUBS.
My Club model is as follows:
use Illuminate\Auth\UserInterface;
use Illuminate\Auth\Reminders\RemindableInterface;
class Club extends Eloquent implements UserInterface, RemindableInterface {
protected $table = 'clubs';
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;
}
// set validation
public static $createUpdateRules = array(
'name'=>'required|min:2',
'location'=>'required|min:2',
'colour'=>'required|min:2',
'alias'=>'required|min:2'
);
// We can define a many-to-many relation using the belongsToMany method:
public function fixtures() {
return $this->belongsToMany('Fixture', 'clubs_fixtures')->withPivot('opponent_id');
}
}
My Fixture model is as follows:
use Illuminate\Auth\UserInterface;
use Illuminate\Auth\Reminders\RemindableInterface;
class Fixture extends Eloquent implements UserInterface, RemindableInterface {
protected $table = 'fixtures';
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;
}
// set validation
public static $createRules = array(
'type'=>'required|min:2',
'opponent'=>'required|min:1',
'date'=>'required|min:2',
'time'=>'required|min:2',
'venue'=>'required|min:2',
'address'=>'required|min:2',
'reminders'=>'required'
);
}
Then in my controller I use Elequent ORM to get the upcoming fixtures
public function getViewClub($id) {
$upcomingFixtures = Club::find($id)->fixtures()->where('date', '>=', new DateTime('today'))->get();
return View::make('club.view')->with('upcomingFixtures', $upcomingFixtures);
}
#foreach($upcomingFixtures as $upcomingFixture)
<p>
<a href="{{ URL::to('dashboard/'.$club->id.'/fixtures/upcoming/'.$upcomingFixture->id) }}">
<strong>{{ $club->name }} vs Team Name</strong>
</a>
</p>
#endforeach
I hope I make sense with all this. I've tried to separate out the data, trying to keep the clean modular and dry, but I've immediately hit a problem here.
Hopefully a Laravel guru can steer me in the right direction here?
Thanks

You're doing it wrong, first you don't need to implement UserInterface and RemindableInterface (but keep it in User model ), second you can add relation clubs() inside your Fixture model
class Fixture extends Eloquent {
protected $table = 'fixtures'; // you can also remove this line
// set validation
public static $createRules = array(
'type'=>'required|min:2',
//....
);
public function clubs() {
return $this->belongsToMany('Club','clubs_fixtures')
->withPivot('opponent_id');
}
}
Then in your controller
public function getViewClub($id) {
$upcomingFixtures = Fixture::with('clubs')
->where('date', '>=', new DateTime('today'))->get();
return View::make('club.view',compact('upcomingFixtures'));
}
#foreach($upcomingFixtures as $upcomingFixture)
<h1>{{ $upcomingFixture->type }}</h1>
#foreach($upcomingFixture->clubs as $club)
<p>
<a href="{{ URL::to('dashboard/'.$club->id.'/fixtures/upcoming/'.$upcomingFixture->id) }}">
<strong>{{ $club->name }} vs Team Name</strong>
</a>
</p>
<p> access to pivot table: {{ $club->pivot->opponent_id }}</p>
#endforeach
#endforeach

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

laravel 9.0 Eloquent all() method doesn't return relationship

I have two tables Department and InspectionSite.
Department Migration
public function up()
{
Schema::create('departments', function (Blueprint $table) {
$table->id();
$table->string('department_name', 100);
});
}
InspectionSite Migration:
public function up()
{
Schema::create('inspection_sites', function (Blueprint $table) {
$table->id();
$table->string('site_title');
$table->foreignIdFor(\App\Models\Department::class);
$table->timestamps();
});
}
Department Model:
class Department extends Model
{
use HasFactory;
protected $fillable = ['depatment_name'];
public function sites() {
return $this->hasMany(InspectionSite::class);
}
}
InspectionSite Model
class InspectionSite extends Model
{
use HasFactory;
protected $guarded = [];
public function department() {
return $this->belongsTo(Department::class, 'department_id');
}
}
getting data from controller
public function get() {
$selector = ['site_title AS title', 'site_type' ];
$sites = InspectionSite::all();
return response()->json($sites->department, 200);
}
when I call find() method it returns relationship data but not in all() method?
public function get() {
$departments = Department::all();
return response()->json($departments->sites, 200);
}
Error details
all() method returns Collection of models and each model should have department relation.
When you are trying to return this:
return response()->json($sites->department, 200);
You are accessing department property on Collection instance.
Instead you should call it on each model of that collection.
Here you can try solutions, depending what you want to achieve
Solution 1: (recomended)
$sites = InspectionSite::with('department')->get();
return response()->json($sites, 200);
// result
[
{
...
department: ...
}
...
]
Solution 2: (Returns only depertments, not InspectionSite properties)
$sites = InspectionSite::with('department')->get()
->map(function($s) {
return $s->department;
});
return response()->json($sites, 200);
// result
[
{
[department]
}
{
[department]
}
]

Is there an easier way to code laravel eloquent models besides what I have here?

I created this code to work with laravel 5.8 to access a database with many foreign keys, seems like I am subverting the foreign keys, am I missing something, was hoping someone could point me in the right direction.
It works, but I think I am overdoing it and missing some eloquent shortcuts.
namespace App\Models\Entities;
use Illuminate\Database\Eloquent\Model;
class AbstractModel extends Model
{
public function isDuplicate(Model $model) {
return $model::where($model->getAttributes())->first();
}
}
///
namespace App\Models\Entities;
abstract class AbstractForeignModel extends AbstractModel {
public $timestamps = false;
public $fillable = ['value'];
public function store($value){
$foreign = $this->newInstance();
$foreign->value = $value;
if(!$this->isDuplicate($foreign)){
$foreign->save();
}
return $foreign->getId($value);
}
public function setValueAttribute($value){
$this->attributes['value'] = $value;
}
public function getId($value){
$result = self::where('value', $value)->first();
if($result){
return $result->id;
}
}
public function getValue($id){
$result = self::where('id', $id)->first();
if($result){
return $result->value;
}
}
}
///
namespace App\Models\Entities\Video;
use App\Models\Entities\AbstractForeignModel;
class ForeignModel extends AbstractForeignModel {
public function video() {
return $this->belongsTo('App\Models\Entities\Video');
}
}
Author, Description, Source, Title extend the above as empty classes
use App\Models\Entities\Video\Author;
use App\Models\Entities\Video\Description;
use App\Models\Entities\Video\Source;
use App\Models\Entities\Video\Title;
use Carbon\Carbon;
class Video extends AbstractModel {
protected $fillable = ['author_id', 'title_id', 'description_id',
'source_id', 'published_at'];
public function store($data) {
$video = new Video;
$video->author_id = $data->author;
$video->title_id = $data->title;
$video->description_id = $data->description;
$video->source_id = $data->source;
$video->published_at = $data->published_at;
if (!$this->isDuplicate($video)) {
$video->save();
}
}
public function setPublishedAtAttribute($value){
$this->attributes['published_at'] = Carbon::parse($value)->toDateTimeString();
}
public function setTitleIdAttribute($value) {
$this->attributes['title_id'] = (new Title)->store($value);
}
public function setDescriptionIdAttribute($value) {
$description = (new Description)->store($value);
$this->attributes['description_id'] = $description;
}
public function setSourceIdAttribute($value) {
$this->attributes['source_id'] =(new Source)->store($value);
}
public function setAuthorIdAttribute($value) {
$this->attributes['author_id'] = (new Author)->store($value);
}
public function getAuthorIdAttribute($value) {
$this->attributes['author_id'] = (new Author)->getValue($value);
}
public function getTitleIdAttribute($value) {
$this->attributes['title_id'] = (new Title)->getValue($value);
}
public function getDescriptionAttribute($value) {
$this->attributes['description_id'] = (new Description)->getValue($value);
}
public function getSourceIdAttribute($value) {
$this->attributes['source_id'] = (new Source)->getValue($value);
}
public function author() {
return $this->belongsTo('App\Models\Entities\Video\Author', 'author_id');
}
public function description() {
return $this->belongsTo('App\Models\Entities\Video\Description', 'description_id');
}
public function title() {
return $this->belongsTo('App\Models\Entities\Video\Title', 'title_id');
}
public function source() {
return $this->belongsTo('App\Models\Entities\Video\Source', 'source_id');
}
}
video migration file
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateVideosTable extends Migration {
public function up() {
Schema::create('videos', function (Blueprint $table) {
$table->bigIncrements('id');
$table->unsignedBigInteger('source_id');
$table->unsignedBigInteger('title_id');
$table->unsignedBigInteger('description_id');
$table->unsignedBigInteger('author_id');
$table->dateTimeTz('published_at');
$table->timestamps();
$table->foreign('source_id')->references('id')->on('sources');
$table->foreign('title_id')->references('id')->on('titles');
$table->foreign('description_id')->references('id')->on('descriptions');
$table->foreign('author_id')->references('id')->on('authors');
});
}
public function down() {
Schema::dropIfExists('videos');
}
}
The foreign key migration files follow this layout for Author, Description, Source, Title
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateTitlesTable extends Migration
{
public $timestamps = false;
public function up()
{
Schema::create('titles', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('value');
});
}
public function down()
{
Schema::dropIfExists('titles');
}
}
could probably create a foreign migration class and just set the variables that I need
What you're probably looking for is firstOrCreate
There are two other methods you may use to create models by mass
assigning attributes: firstOrCreate and firstOrNew. The firstOrCreate
method will attempt to locate a database record using the given column
/ value pairs. If the model can not be found in the database, a record
will be inserted with the attributes from the first parameter, along
with those in the optional second parameter.
The firstOrNew method, like firstOrCreate will attempt to locate a
record in the database matching the given attributes. However, if a
model is not found, a new model instance will be returned. Note that
the model returned by firstOrNew has not yet been persisted to the
database. You will need to call save manually to persist it.

access laravel 5.2 many to many pivot . but it returns null

I am trying to access the middle table attributes of many to many relationships using pivot but it return nulls.
class User extends Modal
{
public function packages()
{
return $this->belongsToMany('App\Package');
}
}
Class Package extend Model
{
public function users()
{
return $this->belongsToMany('App\User');
}
}
$package->pivot->created_at
but it returns null.
although i have a package associated to user.
By default, only the model keys will be present on the pivot object. If your pivot table contains extra attributes, you must specify them when defining the relationship:
public function packages()
{
return $this->belongsToMany('App\Package')->withPivot('created_at');
}
public function users()
{
return $this->belongsToMany('App\User')->withPivot('created_at');
}
Docs
Try this one:
class User extends Modal
{
public function packages()
{
return $this->belongsToMany('App\Package')->withTimestamps();
}
}
Class Package extend Model
{
public function users()
{
return $this->belongsToMany('App\User')->withTimestamps();
}
}
Make sure you have timestamps in your table.
Schema::table('user_package', function (Blueprint $table) {
$table->timestamps();
});
you can do this by adding in your migrations
class User extends Modal
{
public function packages()
{
return $this->belongsToMany('App\Package')->withTimestamps();
}
}
Class Package extend Model
{
public function users()
{
return $this->belongsToMany('App\User')->withTimestamps();
}
}
if you dont add this line your timestamps will not be saved in database.
return $this->belongsToMany('App\User')->withTimestamps();
Hope this helps.

Laravel 4 : Authentication when having a many to many relationship

I have a users, roles and role_users table. In the roles table I have a user and admin value. Now I want to be able to edit users when the role of a user is admin. I don't know how to access the role_name == 'admin' in laravel.
When I use this it works :
#if(Auth::user()->user_username == 'Gilko')
But I want to be able to access this role_name == 'admin'
role_users migration
public function up()
{
Schema::create('role_users', function($table)
{
$table->increments('role_user_id');
$table->integer('role_id')->unsigned();
$table->integer('user_id')->unsigned();
});
Schema::table('role_users', function($table)
{
$table->foreign('role_id')
->references('role_id')->on('roles');
//->onDelete('cascade');
$table->foreign('user_id')
->references('user_id')->on('users');
//->onDelete('cascade');
});
}
User model :
class User extends Eloquent implements UserInterface, RemindableInterface {
protected $table = 'users';
protected $primaryKey = 'user_id';
protected $hidden = ["password"];
public function getAuthIdentifier()
{
return $this->getKey();
}
public function getAuthPassword()
{
return $this->user_password;
}
public function getReminderEmail()
{
return $this->email;
}
public function user()
{
return $this->hasMany('Checklist', 'user_id', 'user_id');
}
public function roles(){
return $this->belongsToMany('Role', 'role_users', 'user_id', 'role_id');
}
public function getRememberToken()
{
//return $this->remember_token;
}
public function setRememberToken($value)
{
//$this->remember_token = $value;
}
public function getRememberTokenName()
{
//return 'remember_token';
}
}
You should be able to do something like this:
if (Auth::user()->roles()->where('name', 'admin')->first())
first will return null if there's no result.
You can also use firstOrFail: http://laravel.com/docs/eloquent
try (Auth::user()->roles()->where('name', 'admin')->firstOrFail()) {
// User has admin role
} catch (ModelNotFoundException $e) {
// User doesn't have admin role
}
Edit Just realized I had a brain fart. Corrected the code :-)
You can add a function which checks for this on your user model...
public function isAdmin()
{
return (bool)$this->roles()->where('name', 'admin')->count();
}
And then you can easily use it with...
#if(Auth::user()->isAdmin())

Categories