Laravel Eloquent Relationship with different foreign key - php

Laravel version is 7.0:
I have setup model relationships like this.
<?php
namespace App;
class Template extends Model
{
protected $fillable = ['header_id', 'content', 'name'];
public function header()
{
return $this->belongsTo('App\Header', 'header_id');
}
}
In controller I can get template object with header.
<?php
namespace App\Http\Controllers;
use App\Template;
class TemplateController extends Controller
{
public function show($id)
{
$template = Template::find($id);
}
}
Now I can use $template->header in view.
How can I pass different header_id and get header relationship object?
I would like to do as following:
<?php
namespace App\Http\Controllers;
use App\Template;
class TemplateController extends Controller
{
public function show($id, $temp_header_id)
{
$template = Template::find($id);
$template->header_id = $temp_header_id;
}
}
I want to get new header relationship in view:
Is there any way to return new header relationship when I do $template->header in view.
Thank you

Yes you can do what you are looking to do, but kinda defeats the relationship in the database. You can assign any id to $template->header_id and then load the relationship using that new value:
$template->header_id = 897;
// load the relationship, will use the new value
// just in case the relationship was already loaded we make sure
// to load it again, since we have a different value for the key
$template->load('header');
$template->header; // should be header with id = 897

Related

How to get data for one to many relationship using Eloquent in Laravel?

How to get data for one to many relationship using Eloquent in Laravel? Actually I followed Eloquent Documentation. But my code returns me an empty array. Here's my work:
Database Schema
Parent Table: mtg_workspace with columns (mw_id[primary key], mw_name,..., mw_access)
Child Table: mtg_workspace_amenities with columns (id[primary key], wa_mwid, wa_name)
Model: MtgWorkspace.php
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class MtgWorkspace extends Model
{
protected $table = 'mtg_workspace';
public $timestamps = false;
public function MtgWorkspaceAmenities(){
return $this->hasMany('App\MtgWorkspaceAmenities', 'wa_mwid');
}
}
Model: MtgWorkspaceAmenities.php
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class MtgWorkspaceAmenities extends Model
{
protected $table = 'mtg_workspace_amenities';
public $timestamps = false;
public function MtgWorkspace(){
return $this->belongsTo('App\MtgWorkspace');
}
}
Controller: WorkspaceController.php
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\MtgWorkspace;
use App\MtgWorkspaceAmenities;
class WorkspaceController extends Controller
{
public function index()
{
$workspace = MtgWorkspace::with('MtgWorkspaceAmenities')->get();
return $workspace;
}
}
and here it shows following output:
Can you try defining the primary key for the MtgWorkspace model (as it is not id):
protected $primaryKey = 'mw_id';
I don't think it can match up the children MtgWorkspaceAmenities to the parent MtgWorkspace models as it is trying to use the id attribute on MtgWorkspace to match to the foreign key on MtgWorkspaceAmenities when it spins through the result of the eager loading.
Side Note:
You will have to pass more parameters to the inverse relationship on MtgWorkSpaceAmenities when defining it, as belongsTo() wants to use the calling methods name snake cased with _id added if not told otherwise as the key.

Laravel 5.5 MassAssignmentException

I'm following the Laravel From Scratch tutorial series, I'm currently at the part that you are creating a comment system for your articles system. But I'm having a problem, I don't really know what the error is saying at this point.
The error:
Illuminate\Database\Eloquent\MassAssignmentException
body
The comment model:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Comment extends Model
{
public function post()
{
return $this->belongsTo(Post::class);
}
}
The post model:
<?php
namespace App;
class Post extends Model
{
public function comments()
{
return $this->hasMany(Comment::class);
}
public function addComment($body)
{
$this->comments()->create(compact('body'));
}
}
The route I made:
Route::post('/posts/{post}/comments', 'CommentsController#store');
The comments controller:
<?php
namespace App\Http\Controllers;
use App\Post;
class CommentsController extends Controller
{
public function store(Post $post)
{
$post->addComment(request('body'));
return back();
}
}
Thanks in advance!
Explanation of this error
This is a security feature of Laravel. It is designed to protect you against form manipulation when using mass assignments.
For example on a sign-up form: When you have an is_admin column in your database, a user simply could manipulate your form to set is_admin to true on your server, and therefore in your database. This security feature prevents that by using a whitelist to define safe fields.
How to fix that
You need to set a $fillable property on your model. It's value must be an array containing all fields that are safe to mass assignable (like username, email address, ...).
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Comment extends Model
{
# This property!
protected $fillable = ['body'];
// ...
}
See "Mass assignment" in the docs:
https://laravel.com/docs/5.5/eloquent#mass-assignment
Mass assignment is when you send an array to the model creation, basically setting a bunch of fields on the model in a single go, rather than one by one, something like what you did here:
public function addComment($body)
{
$this->comments()->create(compact('body'));
}
You need to add the field you are populating to the fillable array in Comments.php model:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Comment extends Model
{
protected $fillable = ['body'];
public function post()
{
return $this->belongsTo(Post::class);
}
}
As the documentation states:
You may also use the create method to save a new model in a single
line. The inserted model instance will be returned to you from the
method. However, before doing so, you will need to specify either a
fillable or guarded attribute on the model, as all Eloquent models
protect against mass-assignment by default.
Hope this helps you.

Laravel 5 - How do I return a oneToMany relationship?

I'm new to Laravel, and using Laravel 5 i'm having trouble returning an array from my database.
I have several "acts", and each act has many "banners". Whenever I try to get output from my array of banners ( $act->banners->count() ), i find it throws an error because it is null.
Here is the code:
routes.php:
Route::model('banners', 'Banner');
Route::model('acts', 'Act');
// Controller routes
Route::resource('acts', 'sf_ActController');
Route::resource('acts.banners', 'sf_BannerController');
Route::bind('banners', function($value, $route) {
return App\Banner::whereact_id($value)->first();
});
Route::bind('acts', function($value, $route) {
return App\Act::whereact_id($value)->first();
});
Act.php (model)
namespace App;
use Illuminate\Database\Eloquent\Model;
class Act extends Model
{
protected $table = 'sf_act';
protected $primaryKey = 'act_id';
public function act() {
return $this->hasMany('Banner');
}
}
Banner.php (model)
namespace App;
use Illuminate\Database\Eloquent\Model;
class Banner extends Model
{
protected $table = 'sf_banner';
protected $primaryKey = 'banner_id';
public function banner() {
return $this->belongsTo('Act' , 'act_id' , 'act_id');
}
}
sf_ActController.php (controller)
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Act;
use App\Banner;
use App\Http\Requests;
use App\Http\Controllers\Controller;
use Input;
use Redirect;
class sf_ActController extends Controller
{
public function show(Act $act)
{
//pass object to correct view
return view('pages.acts.show' , compact('act'))->with('banner', Banner::find($act));
}
acts/show.blade.php (view)
<!-- /resources/views/acts/show.blade.php -->
#extends('app')
#section('content')
<h2>{{ $act->act_title }}</h2>
{{ $act->banners->count() }}
at this point I get the following error:
FatalErrorException in a03036ad81fb4e6d90e9fe5e3da62c65 line 7:
Call to a member function count() on null
Why am I not fetching my banner data!? (The title variable in the h2 tags outputs fine, so the db and everything up until that point is working.)Thanks.
You need to specify the complete "route" to the model in the relationships including the namespace:
public function act() {
return $this->hasMany('App\Banner');
}
And the same on belongsTo:
public function banner() {
return $this->belongsTo('App\Act' , 'act_id' , 'act_id');
}
Could be a good idea to include the name of the foreign kay in the hasMany method.
public function act() {
return $this->hasMany('App\Banner', 'act_id');
}
Also possibly you don't need to include the third parameter in the belongs to.
Hope it helps. Also can share with you a link to learn about Laravel step-by-step: Learn Laravel 5.0 => 5.1
You currently have your hasMany relationship setup like this:
public function act() {
return $this->hasMany('Banner');
}
However in your view your calling this relationship:
$act->banners->count()
Shouldn't it be:
$act->act()->count();

Get all records in cakephp3 using TableRegistry?

My Demo Controller (DemoController.php):
<?php
namespace App\Controller;
class DemoController extends AppController
{
public function users()
{
$this->loadmodel('registration');
$result = $this->registration->getAllUsers();
$this->set('user_data',$result)
}
}
?>
My registration model (registration.php):
<?php
namespace App\Model;
use Cake\ORM\TableRegistry;
class Registration extends AppModel {
$articles = TableRegistry::get('registration');
public function getAllUsers()
{
return $query = $articles->find();
}
}
?>
My View:
path -- src/Template/Demo/users.ctp
but it's getting error like this (in below image) --
Your model should be named RegistrationsTable, and be in src/Model/Table/RegistrationsTable.php. Load it with loadModel('Registrations'). (It's your entity that should be named Registration.) To use your custom finder method, name the function findAllUsers, fix the signature per the documentation (should take two parameters: Query $query, array $options) and call it as $this->Registration->find('all_users');.
And why are you trying to initialize a $articles variable as the registrations model inside the registrations model (but outside of any function)? So much mess...

Laravel 5 database relationship accessing a data on another table

I have this kind of database design
user_classes
- id
- user_id
- class_schedule_id
class_schedules
- id
- class_id
- date
classes
- id
- name
I am now in my UserClass.php Model File
public function classSchedule() {
return $this->belongsTo('\App\ClassSchedule');
}
public static function getClassByUser($user_id){
$user_class = self::where('user_id','=',$user_id)->with('classSchedule');
//other codes here...
}
My question here is that how can I access the name of the class in the class table since the user_classes table doesn't have a direct access to the class instead it should go through first to the class_schedules table.
I am not sure what Eloquent ORM Relationship should I use.
Your help will be greatly appreciated!
thanks! :)
First of all you will need to rename the third class, from class to something else. Then try this,
class user_classes Extends Eloquent {
function classSchedule() {
return $this->hasMany('Class_schedules','class_schedule_id');
}
}
class class_schedules Extends Eloquent {
function userClasses() {
return $this->belongsTo('user_classes', 'class_schedule_id');
}
function classSomething() {
return $this->hasOne('class_something','id');
}
}
class class_something Extends Eloquent {
function classSchedules() {
return $this->belongsTo('class_schedules', 'id');
}
}
Try and follow the naming conventions within Laravel, that will make your life easier down the road.
It uses the snake_cased version of the plural of your model name to define the table name automagically.
Besides that, when you have a relation with single or plural output, name your relation methods accordingly to describe what they do and what kind of output you can expect.
I prefer a dir /app/Models for the models, hence the namespace, you can change this to /app if that's where your models are.
<?php namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class UserClass extends Model
{
// only defined because laravel auto generates alphabetically
protected $table = 'user_classes';
public function user()
{
// given that User model was moved to app/Models, if not, use \App\User
return $this->belongsTo('\App\Models\User');
}
public function classSchedule()
{
return $this->belongsTo('\App\Models\ClassSchedule');
}
}
<?php namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class ClassSchedule extends Model
{
public function class()
{
return $this->belongsTo('\App\Models\Class');
}
}
<?php namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Class extends Model
{
public function classSchedules()
{
return $this->hasMany('\App\Models\ClassSchedule');
}
}
Now you can basically fetch all entries of UserClass for a particular user, with or without eager loading...
$userClasses = UserClass::where('user_id', $userId)->get();
$userClasses->map(function($userClass) {
echo $userClass->classSchedule->class;
});
More preferably you'll have a method userClasses() with a hasMany relation in your user model

Categories