I am using Laravel 5.3 ad having issues on saving through the hasMany relationship.
I have tables job and jobsite which has One-to-Many Relation i.e Each jobsite has one or many jobs
but when I am trying to add job_job_site_id in the job table using associate() it send me an error:
SQLSTATE[42703]: Undefined column: 7 ERROR: column "job_site" of relation "job" does not exist
LINE 1: update "job" set "updated_at" = $1, "job_site" = $2 ...
^ (SQL: update "job" set "updated_at" = 2016-11-13 15:29:37, "job_site" = where "job_id" = 3)
SQLSTATE[42703]: Undefined column: 7 ERROR: column "job_site" of relation "job" does not exist
LINE 1: update "job" set "updated_at" = $1, "job_site" = $2 ...
^
Database structure:
job (1st table)
– job_id
– job_name
– job_job_site_id
- created_at
- updated_at
job_site (2nd table)
– job_site_id
– job_site_name
- created_at
- updated_at
Model Class Job:
class Job extends Model
{
protected $table = 'job';
protected $primaryKey = 'job_id';
public function jobsite() {
return $this->belongsTo('App\Models\JobSite', 'job_site', 'job_job_site_id', 'job_site_id');
}
}
Model Class JobSite:
class JobSite extends Model
{
protected $table = 'job_site';
protected $primaryKey = 'job_site_id';
public function jobs() {
return $this->hasMany('App\Models\Job', 'job', 'job_job_site_id', 'job_id');
}
}
Controller:
public function jobsiteJobs($data)
{
$jobsite = JobSite::find(3);
$job_id = array(1,2,3);
if (!empty($jobsite)) {
foreach ($job_id as $id) {
$job = Job::find($id);
$job->jobsite()->associate($jobsite);
$job->save();
}
return 'Added';
}
else {
return 'Not found';
}
}
Do I have my relationship defined incorrectly here?
Yes, your have defined relationships incorrectly. The correct version is following:
Model Class Job:
class Job extends Model
{
protected $table = 'job';
protected $primaryKey = 'job_id';
public function jobsite() {
return $this->belongsTo('App\Models\JobSite', 'job_job_site_id', 'job_site_id');
}
}
Model Class JobSite:
class JobSite extends Model
{
protected $table = 'job_site';
protected $primaryKey = 'job_site_id';
public function jobs() {
return $this->hasMany('App\Models\Job', 'job_job_site_id', 'job_site_id');
}
}
Related
I'm trying to create a league table in Laravel but I'm running into some issues with guess what, relationships, again. They never seem to work for me in Laravel. It's like they hate me.
I have a modal for matches
<?php
namespace App\Database;
use Illuminate\Database\Eloquent\Model;
class Match extends Model
{
protected $primaryKey = 'id';
protected $table = 'matches';
public $timestamps = false;
protected $guarded = ['id'];
}
And a modal for teams, but with a matches() function
<?php
namespace App\Database;
use Illuminate\Database\Eloquent\Model;
class Team extends Model
{
protected $primaryKey = 'id';
protected $table = 'teams';
public $timestamps = false;
protected $guarded = ['id'];
public function matches() {
return $this->hasMany('App\Database\Match', 'team_one_id, team_two_id');
}
}
I think the issue comes with team_one_id, team_two_id as the teams primary key could be in either one of them columns for the other table. When calling count() on matches() it throws an error.
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'matches.team_one_id, team_two_id' in 'where clause' (SQL: select count(*) as aggregate from matches where matches.team_one_id, team_two_id = 1 and matches.team_one_id, team_two_id is not null)
can you try this syntax
return $this->hasMany('modelPath', 'foreign_key', 'local_key');
Does Match table have a column maned 'team_id'?
because it's the default naming convention in the laravel docs for mapping the tables.
if you do have the column and populate the data you can just remove the foreign & local keys from matches() relationship. you don't need it. Laravel will automatically map it for you.
if you do not have the 'team_id' on Matches table please add the column and add the respective team ids for matches.
<?php
namespace App\Database;
use Illuminate\Database\Eloquent\Model;
class Team extends Model
{
protected $primaryKey = 'id';
protected $table = 'teams';
public $timestamps = false;
protected $guarded = ['id'];
public function matches() {
return $this->hasMany('App\Database\Match');
}
}
This way you can implement it, Add these relationship and a method in Team Model
public function homeMatches() {
return $this->hasMany('App\Database\Match', 'team_one_id');
}
public function awayMatches() {
return $this->hasMany('App\Database\Match', 'team_two_id');
}
public function matches() {
return $this->homeMatches->merge($this->awayMatches);
}
Now Fetch the data
$team = Team::find(1);
$matches = $team->matches(); //now it will fetch all matches for both columns
If you want to fetch matches as attributes then you can add one method
in your Team model
public function getMatchesAttribute()
{
return $this->homeMatches->merge($this->awayMatches);
}
Now you can fetch the matches as $matches = $team->matches;
Here is the difference
$team->matches returns Illuminate\Database\Eloquent\Collection
And
$team->matches() returns Illuminate\Database\Eloquent\Relations\{Relation Name}
You can't use matches in Eager loading like Team::with('matches') because matches is not a relationship and that causing your Error. What you can do is add homeMatches and awayMatches in eager loading and then call $team->matches().
$teams = Team::with('homeMatches', 'awayMatches')->get();
$teams->each(function ($team) {
print_r($team);
print_r($team->matches());
});
I'm trying to do browser game like Tribal Wars in Laravel.
I want to get building level by using $wioska->buildings->Tartak->level, but something not working:
This is my Building model:
class Building extends Model
{
protected $table = 'budynki';
public function Tartak(){
return $this->hasOne('App\Tartak');
}
}
Wioska (village) model:
class Wioska extends Model
{
protected $fillable = ['name', 'user_id'];
protected $table = 'wioski';
public function user(){
return $this->belongsTo('App\User');
}
public function buildings(){
return $this->hasOne('App\Building');
}
}
And this is my Tartak model:
class Tartak extends Model
{
protected $table = 'budynki';
public function level(){
$u = Auth::user();
$id = $u->wioska->id;
return DB::table('budynki')->where('wioska_id', $id)->first();
}
}
Migration "budynki":
public function up()
{
if(!Schema::hasTable('budynki')) {
Schema::create('budynki', function (Blueprint $table) {
$table->integer('town_hall')->default(1);
$table->integer('iron')->default(0);
$table->integer('wood')->default(0);
$table->integer('stone')->default(0);
$table->integer('bread')->default(0);
$table->integer('wioska_id');
$table->foreign('wioska_id')->references('id')->on('wioski');
});
}
}
1) It's always good to check for a null entity before trying to call its methods. Example, if $wioska->buildings is null or wioska has no buildings, or buildings have no Tartak, then the rest of the line will throw errors.
2) level() is a method and since its not an authentic Laravel relationship, you will need to use it as a method, example - $wioska->buildings->Tartak->level()
level is not property as per your model, so you have to try as below
$wioska->buildings->Tartak->level()
Now I've got
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'budynki.building_id' in 'where clause' (SQL: select * from budynki where budynki.building_id is null and budynki.building_id is not null limit 1) error
I just want to get tartak level from budynki table: https://i.imgur.com/zoTx5tE.png .
here is an example
Table Structure
Game
--id
--game
Posts
--id
--game_id
--post_text
class Posts extends Eloquent {
protected $primaryKey = 'id';
protected $table = 'posts';
public function games() {
return $this->hasOne('games','id');
}
}
class Games extends Eloquent {
protected $primaryKey = 'id';
protected $table = 'games';
public function posts() {
return $this->belongsTo('posts','game_id');
}
}
I need to get the game name of a certain post. How can I get it using eloquent?
here is my initial code
echo $post->games['game'];
but I get the wrong data.
The way it queries is this.
'query' => string 'select * from `games` where `games`.`id` = ? limit 1' (length=52)
'bindings' =>
array (size=1)
0 => int 5
Firstly Eloquent model names are not plural, so by default they should be Game and Post.
Secondly relationship return values must be changed. In hasOne and belongsTo you will need to use model class names like below. I also left out some optional code which is not required for the code to work.
class Post extends Eloquent {
public function game() {
return $this->hasOne('Game');
}
}
class Game extends Eloquent {
public function post() {
return $this->belongsTo('Post');
}
}
Now you can get the game name by $post->game->name
I have the following relations:
Discount:
<?php
class Discount extends Eloquent {
protected $table = 'discount';
public $timestamps = true;
public function title()
{
return $this->hasOne('Translation', 'labelId', 'titleLabelId')->where('languageId', T::getLang())->first()['phrase'];
}
public function titles()
{
return $this->hasMany('Translation', 'labelId', 'titleLabelId');
}
}
?>
Translation:
<?php
class Translation extends Eloquent {
protected $table = 'translations';
public $timestamps = false;
protected $fillable = array('phrase', 'languageId', 'labelId');
public function language()
{
return $this->belongsTo('Language', 'languageId');
}
public function label()
{
return $this->belongsTo('Label', 'labelId');
}
}
?>
Label:
<?php
class Label extends Eloquent {
protected $table = 'label';
public $timestamps = false;
protected $fillable = array('key');
public function translations()
{
return $this->hasMany('Translation', 'labelId', 'id');
}
}
?>
There are three database tables with the following columns:
Discount:
id | titleLabelId
Translation:
id | languageId | labelId
Label:
id
The problem: I'd like to create a title (translation) and associate it with the discount. Here's what I've tried:
$discount = new Discount;
/*create a new label*/
$labelKey = Label::max('key') + 1;
$label = new Label(array('key' => $labelKey));
$label->save();
/*create a new title (and associate it with the label)*/
$title = new Translation(
array(
'phrase' => $input['title'],
'languageId' => 3,
'labelId' => $label->id
));
$title->save();
$discount->save();
$discount->titles()->save($title);
Apparently, the $discount->titles()->save($title); part doesn't work. The title is only attached to the discount if I do it manually: $discount->titleLabelId = $label->id. Is there a way to do it using the ORM?
In your Discount Model, do you have your relationship set up to use the proper table and foreign key?
class Discount extends Eloquent
{
public function titles()
{
return $this->belongsTo('Translation', 'translations', 'titleLabelId');
}
}
When trying to associate one model with another through a defined relationship in Eloquent, you should use the associate() method rather than the save() method.
$discount->titles()->associate($title);
Before this happens though, you should be sure to call the save() method on anything that has been altered or is new.
I'm having trouble figuring out how to access a nested relationship within Laravel. The specific example I have is a Movie that has many entires in my Cast table which has one entry in my People table. These are my models:
MOVIE
class Movie extends Eloquent {
protected $primaryKey = 'movie_id';
protected $table = 'movie';
// Relationships
public function cast()
{
return $this->hasMany('MovieCast', 'movie_id');
}
}
MOVIECAST
class MovieCast extends Eloquent {
protected $table = 'movie_cast';
public function person()
{
return $this->hasOne('Person', 'person_id');
}
public function netflix()
{
return $this->belongsTo('Movie', 'movie_id');
}
}
PERSON
class Person extends Eloquent {
protected $primaryKey = 'person_id';
protected $table = 'people';
public function movieCast()
{
return $this->belongsTo('MovieCast', 'person_id');
}
}
In my controller I can access the cast (containing person_id and role_id) like so:
public function movie($id)
{
$movie = Movie::find($id);
$cast = $movie->cast();
return View::make('movie')->with(array(
'movie' => $movie,
'cast' => $cast
));
}
...but I don't know how to access the corresponding name field in my People table.
EDIT 1:
Using the classes exactly as defined below in #msturdy's answer, with the controller method above I try to render the person names like so inside my view:
#foreach($cast->person as $cast_member)
{{$cast_member->person->name}}
#endforeach
Doing this i get the error:
Undefined property: Illuminate\Database\Eloquent\Relations\HasMany::$person
I don't know if it makes a difference or not but I have no id field on my People table. person_id is the primary key.
It should be simple, once you have accessed the cast...
Route::get('movies', function()
{
$movie = Movie::find(1);
$cast = $movie->cast;
return View::make('movies')->with(array(
'movie' => $movie,
'cast' => $cast));
});
Note: at this point, $cast is an instance of the Collection class, not a single object of the MovieCast class, as the
relationship is defined with hasMany()
you can iterate over it in the View (in my case /app/views/movies.blade.php
#foreach($cast as $cast_member)
<p>{{ $cast_member->person->name }}</p>
#endforeach
Class definitions used for testing:
class Movie extends Eloquent {
protected $primaryKey = 'movie_id';
protected $table = 'movie';
public $timestamps = false;
// Relationships
public function cast()
{
return $this->hasMany('MovieCast', 'movie_id');
}
}
class MovieCast extends Eloquent {
protected $table = 'movie_cast';
public $timestamps = false;
public function person()
{
return $this->hasOne('Person', 'person_id');
}
}
class Person extends Eloquent {
protected $primaryKey = 'person_id';
protected $table = 'people';
public $timestamps = false;
public function movieCast()
{
return $this->belongsTo('MovieCast', 'person_id');
}
}