Eloquent ORM dynamic table, creating via model fails to select table - php

On the REST API am building based on slim3, I use route parameters to dynamically select a tenant to do certain crud actions on.
The model:
class Customer extends Model {
protected $table = '';
protected $fillable = ['some', 'fields'];
public function setTable($table) {
$this->table = $table;
}
public function getTable() {
return $this->table;
}
}
Selecting and updating entries works (properly) like this:
// selects properly from $tableName table
$kd = new Customer;
$kd->setTable($tableName);
$data = $kd->whereEmail($args['email'])->firstOrFail();
Creation fails, using the same approach:
$kdc = new Customer;
$kdc->setTable($tableName); // it should use dbname.prefix_$tableName same as above
$kdc->create($customerData);
// fails with error Base table or view not found: 1146 Table 'dbname.prefix_' doesn't exist
I have checked that create() successfully calls getTable() from the Model and gets proper value. But it seems not to use it...

Related

How to save In Pivot Table in Laravel

How to save data to pivot table in laravel , I have two tables has many-to-many relationship , so i create pivot table , I tried the sync() method to insert but it keep gives me this exception:
"message": "Call to a member function sync() on null",
"exception": "Symfony\Component\Debug\Exception\FatalThrowableError",
here is Contract Model :
class Contract extends Model
{
public function skills(){
$this->belongsToMany(RequiredSkills::class , 'contract_skills')->withTimestamps();
}
}
and here is RequiredSkills Model :
class RequiredSkills extends Model
{
public function contract(){
$this->belongsToMany(Contract::class , 'contract_skills');
}
}
and here is the controller :
class RequiredSkillsController extends Controller
{
public function store(Request $request){
$contract = new Contract();
$data = $request->all();
$requiredSkills = RequiredSkills::create([
'contract_id'=>$data['contract_id'],
'skills_tag'=>$data['skills_tag'],
'user_id'=>auth()->guard('api')->user()->id
]);
$contract->skills()->sync($requiredSkills->id);
return $requiredSkills;
}
}
how to solve the exception ?
You don't have to write data to the relationship table laravel does it for you
When using the 'sync ()' function Laraval will automatically record the relationship in the "contract_skills" table.
You are not writing Contract to the database so it has no ID, so you will not be able to link
Contract and Skills need to be recorded before you can call
the sync () function will execute the following insert:
insert into [contract_skills] ([contract_id], [skill_id]) values (1, 1)
I would do the store function as follows
class RequiredSkillsController extends Controller
{
public function store(Request $request){
//Create Contract in database
$contract = Contract::create($request->contract);
//Get skills id to link with contract
$data = $request->skills;
//syncs with additional data
$contract->skills()->sync(array_column($data, 'id'), ['user_id'=>auth()->guard('api')->user()->id]);
return $contract->refresh()->skills;
}
}

Base table or view not found: Many to many relation laravel

I have two models setup in many to many relation with pivot tabel climbincludeds_tour:
Tour.php
class Tour extends Model
{
protected $table = 'tours';
public function climbIncluded(){
return $this->belongsToMany('App\ClimbIncluded',
'climbincludeds_tour',
'tour_id', 'cincluded_id');
}
}
ClimbIncluded.php
class ClimbIncluded extends Model
{
protected $table = 'climbincludeds';
public function tours()
{
return $this->belongsToMany('App\Tour');
}
}
And I have a delete button on view attached to destroy method in ClimbIncludedController.php
public function destroy(ClimbIncluded $climbIncluded)
{
$climbIncluded->tours()->detach();
$climbIncluded ->delete();
Session::flash('success','Item sucessfully deleted !');
return redirect()->route('climb.ie');
}
When I want to delete a record laravel returns an error:
SQLSTATE[42S02]: Base table or view not found: 1146 Table 'peak.tour_trek_included'
doesn't exist (SQL: delete from `tour_trek_included` where `trek_included_id` = 1)
If I remove or comment out the $climbIncluded->tours()->detach(); from the destroy method, laravel deletes the record without any error. I have passed name of pivot table as second argument to belongsToMany method also. What am I missing here ?

working on many to many table and more attributes are required in third table

i am trying to save data in third table in many to many relation but
data is not saving
user model
public function Jobs()
{
return $this->belongsToMany('App\Models\Job','App\Models\Job_User','user_id','job_id');
}
job model
public function Users()
{
return $this->belongsToMany('App\Models\User','App\Models\Job_User','job_id','user_id');
}
controller for saving data in third table is
public function JobApplied(Request $request){
$applied= new Job_User();
$applied->user_id = Auth::id();
$applied->job_id = $request->job_id;
$applied->cv = $request->cv;
$applied->current_salary = $request->current_salary;
$applied->expected_salary = $request->expected_salary;
$applied->save();
return redirect('searchjobs');
}
code of third table is
class Job_User extends Model
{
protected $fillable = [
'user_id','job_id','cv','current_salary','expected_salary','status',
];
protected $table = 'jobs_users';
}
You're using the many-to-many relation incorrectly. You don't need a model for the intermediate table as Eloquent will handle it for you.
First of all, you need to define the relation in your models in a correct way. The second argument should be the name of the intermediate table, not the model. As you're using the default values for table name and foreign key column names, you can skip them and just do:
public function Jobs()
{
return $this->belongsToMany('App\Models\Job');
}
public function Users()
{
return $this->belongsToMany('App\Models\User');
}
If you want to have additional fields in the intermediate column, you need to define it when you define a relationship using withPivot() method:
public function Jobs()
{
return $this->belongsToMany('App\Models\Job')->withPivot('cv','current_salary','expected_salary','status');
}
public function Users()
{
return $this->belongsToMany('App\Models\User')->withPivot('cv','current_salary','expected_salary','status');
}
Now, if you want to link a Job with a User and set the fields in the intermediate pivot table, you should use save() method on your relation:
$job->users()->save($user, ['cv' => $request->cv, 'current_salary' => $request->current_salary]);
or
$user->jobs()->save($job, ['cv' => $request->cv, 'current_salary' => $request->current_salary]);
Once you have data saved in your database you can retrieve data from intermediate pivot table using the pivot attribute of related model, e.g.:
foreach($user->jobs as $job) {
echo $job->pivot->current_salary;
}
or
foreach($job->users as $user) {
echo $user->pivot->current_salary;
}
Check the docs for more information about handling many-to-many relationship with Eloquent: https://laravel.com/docs/5.1/eloquent-relationships#many-to-many

Eloquent Query for "BelongsToMany" Relationship

When I want to query for all states a specific dispatch ticket in my database, I would do it like this:
public function test() {
$dispatches = Dispatch::where('dispatch_reference', '=', 'dis_548k14s4glnhv5')->get();
foreach($dispatches->states as $state) {
var_dump($state);
}
}
But this throws an error message, that states is not being recognized. The models I created are:
Dispatch
class Dispatch extends Model {
use EventGenerator;
protected $table = 'dispatches';
protected $fillable = ['dispatch_reference', 'incident_reference', 'state'];
public $timestamps = true;
// Since the FK exists in this table, the belongsTo() method is used to state that the dispatch model is related to an address.
// Dispatch __belongs_to__ Incident
public function incident() {
return $this->belongsTo('App\Classes\Incident');
}
// Dispatch __belongs_to_many__ State
public function states() {
return $this->belongsToMany('App\Classes\DispatchState')->withTimestamps();
}
public function attachDispatchState($id) {
$this->states()->attach($id);
$this->touch();
}
// set fields on the eloquent object and save to database
// raise event that the incident was created.
public function createDispatch($command) {
// Get BodyContent from POST Request
$this->dispatchReference = $command->dispatchReference;
$this->incidentReference = $command->incidentReference;
// Create new Dispatch
$dispatch = Dispatch::create(array(
'dispatch_reference' => $this->dispatchReference,
'incident_reference' => $this->incidentReference
));
$dispatchState = DispatchState::where('state', '=', 'processing')->first();
$dispatch->attachDispatchState($dispatchState->id);
return $this;
}
Dispatch State
class DispatchState extends Model {
use EventGenerator;
// Define Table Setup with fillabe fields
protected $table = 'dispatch_states';
// Fillable fields in database
protected $fillable = ['state'];
// include timestamps
public $timestamps = true;
// Status __belongs_to_many__ Dispatches
public function dispatches() {
return $this->belongsToMany('App\Classes\Dispatch');
}
}
I would expect to see all the different states attached to one dispatch as i am using a pivot table that works fine so far. I just cannot query the results. Do I have an error in my models?
When you're calling get() you're getting a collection of Dispatch object. If you expect to only get a single object (e.g. when dispatch reference is unique), call first() instead of get():
$dispatch = Dispatch::where('dispatch_reference', '=', 'dis_548k14s4glnhv5')->first();
If, however, dispatch reference is not unique, you'll need to first iterate through collection of dispatches and then through their related states:
$dispatches = Dispatch::where('dispatch_reference', '=', 'dis_548k14s4glnhv5')->get();
foreach($dispatches as $dispatch) {
foreach ($dispatch->states as $state) {
var_dump($state);
}
}

relationship array null when eager loading in laravel

I am having issues getting the relationship array back when eager loading in laravel 4. for example:
controller:
foreach (Apps::with('extra')->get() as $app)
{
print_r($app->toArray());//returns array but my relationship array at the bottom says null
echo $app->extra; //this will show my relationship details
}
model:
class Apps extends Eloquent
{
protected $connection = 'mysql_2';
protected $table = 'apps';
public $timestamps = false;
protected $primaryKey = 'name';
public function host()
{
return $this->belongsTo('Hosts','name');
}
public function extra()
{
$this->primaryKey='app_ip';
return $this->hasone('Extra','ip');
}
//other functions below.......
}
class Extra extends Eloquent
{
protected $connection = 'mysql_3';
protected $table = 'extra';
public $timestamps = false;
protected $primaryKey = 'ip';
public function app(){
return $this->belongsTo('Apps', 'app_ip');
}
mysql:
My mysql tables were not created through laravel they were previously existent. the app_ip column in the Apps table relates to the ip column in the extra table. it is a 1 to 1 relationship and I have specified the primary key in the relationship function. I am getting relationships back so I know that it is working.
I am able to get relationship data back when I call the function directly, but it does not show the relationship data when I try and print the full array. The main goal is to be able to return both the relationship columns and the app columns in one response.
You need to do this:
$apps = Apps::all();
$apps->load('extra');
foreach ($apps as $app)
{
print_r($app->toArray()); // prints your relationship data as well
}
What you have should work and iterating through the collection or using ->load() to eager load shouldn't make a difference. Are you using the visible restriction on your models? If so you will need to include the relationships.
class Apps extends Eloquent {
protected $visible = array(
'id',
'name',
'created_at',
'extra', // Make the relationship 'visible'
);
public function extra()
{
return $this->hasMany('Extra');
}
}

Categories