Relationship use difference connection - php

I need to get data from a different database in a relationship, like so:
Table1::development(1)->with([ 'column' => function($q) {
$q->connection('live');
}])->first()
development is a local scope on my Table1 model, it just performs a where clause.
I'm getting an error with the above code which I can't figure out:
Error: BadMethodCallException: Call to undefined method Illuminate\Database\Query\Builder::connection() in /var/www/vendor/illuminate/database/Query/Builder.php:2445
Can someone help me out?

Managed to figure it out, not sure if it's the best way. I just added my condition to the construct in my model and then swapped the connection there.
/**
* Create a new Eloquent model instance.
*
* #param array $attributes
* #return void
*/
public function __construct(array $attributes = [])
{
parent::__construct();
if (env('MODE') === 'mode2') {
$this->setConnection('live');
}
}

Related

Update a table with composite key using Laravel Eloquent

I am badly stuck in a table with a composite key. I am trying to use the eloquent to filter the record by two primary keys. But I came to know that eloquent doesn't support composite keys. I have gone through many solutions but no solution is clear enough for a beginner to understand.
a solution code says to edit the model class with the following code:
<?php
class CustomerAddress extends Model {
protected function setKeysForSaveQuery(Builder $query)
{
$query
->where('Customer_No', '=', $this->getAttribute('Customer_No'))
->where('Address_Name', '=', $this->getAttribute('Address_Name'));
return $query;
}
}
I want to perform the update function using the resource controller provided by laravel:
my code looks like this:
/**
* Update the specified resource in storage.
*
* #param \Illuminate\Http\Request $request
* #param int $id
* #return \Illuminate\Http\Response
*/
public function update(Request $request, $sem_course_id, $clo_id)
{
$id = $this->getKeyForSaveQuery();
$request->validate([
'assignments_weightage'=>'required',
'quizes_weightage'=>'required',
'project_weightage'=>'required',
'class_participation_weightage'=>'required',
'mid_weightage'=>'required',
'final_weightage'=>'required',
]);
$course = CoursesMarksScheme::find($clo_id,$sem_course_id);
$course->assignments_weightage = $request->get('assignments_weightage');
$course->quizes_weightage = $request->get('quizes_weightage');
$course->project_weightage = $request->get('project_weightage');
$course->class_participation_weightage = $request->get('class_participation_weightage');
$course->mid_weightage = $request->get('mid_weightage');
$course->final_weightage = $request->get('final_weightage');
$course->save();
return redirect('/coursesmarks');
}
Also, please guide me on how to use the resource controller with primary keys as it is throwing an error for a few arguments?
Please help me. I am really exhausted reading a lot of online articles but unable to resolve the problem.
As I see solution code which you found is only for update, but don't for find. Laravel support composite key in migrations, but don't in eloquent.
Maybe it is better, use simple solution like this and don't waste time:
CoursesMarksScheme::where(['clo_id' => $clo_id, 'sem_course_id' => $sem_course_id])
->update($request);
I suppose necessary fields are in $fillable variable in CoursesMarksScheme model.

Return relationships in Laravel show route

When I create a CRUD controller, this is the show route created by default:
/**
* Display the specified resource.
*
* #param \App\Team $team
* #return \Illuminate\Http\Response
*/
public function show(Team $team)
{
//
}
$team is an object here, an instance of Team. If I do this I have the correct object passed to blade:
public function show(Team $team)
{
return view('admin.teams.show', ['team' => $team]);
}
But, Team has a many-to-many relationship with another model called Player, and this relationship is defined as such from the Team side:
public function players() {
return $this->belongsToMany(Player::class);
}
In my show method, I'd like to return the $team with its related players. But since $team is already an object and not a query builder, it's too late to do something like
$team->with('players')
So how do I get the related players here? I know I can do something like:
public function show(Team $team)
{
$team_extended = Team::where('id', $team['id'])->with('players')->first();
return view('admin.teams.show', ['team' => $team_extended]);
}
But it feels like hacking a functionality that should be there by default. Is there a built-in Laravel way to do this or am I just inventing hot water and should take the approach I used in my solution above?
If you've already got your Team model loaded, you can load a relationship without having to completely re-create it using the ->load() method:
public function show(Team $team){
$team->load("players");
return view("admin.teams.show", ["team" => $team]);
}
Note however, this isn't required unless you need to modify the default content of $team->players. When you trying to access $team->players say in your admin.teams.show view, if that property doesn't already exist (as it would using ->with(["players"]) or ->load("players"), Laravel will load it automatically.

Am I doing eager loading correctly? (Eloquent)

I have a method that needs to pull in information from three related models. I have a solution that works but I'm afraid that I'm still running into the N+1 query problem (also looking for solutions on how I can check if I'm eager loading correctly).
The three models are Challenge, Entrant, User.
Challenge Model contains:
/**
* Retrieves the Entrants object associated to the Challenge
* #return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function entrants()
{
return $this->hasMany('App\Entrant');
}
Entrant Model contains:
/**
* Retrieves the Challenge object associated to the Entrant
* #return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function challenge()
{
return $this->belongsTo('App\Challenge', 'challenge_id');
}
/**
* Retrieves the User object associated to the Entrant
* #return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function user()
{
return $this->belongsTo('App\User', 'user_id');
}
and User model contains:
/**
* Retrieves the Entrants object associated to the User
* #return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function entrants()
{
return $this->hasMany('App\Entrant');
}
The method I am trying to use eager loading looks like this:
/**
* Returns an array of currently running challenges
* with associated entrants and associated users
* #return array
*/
public function liveChallenges()
{
$currentDate = Carbon::now();
$challenges = Challenge::where('end_date', '>', $currentDate)
->with('entrants.user')
->where('start_date', '<', $currentDate)
->where('active', '1')
->get();
$challengesObject = [];
foreach ($challenges as $challenge) {
$entrants = $challenge->entrants->load('user')->sortByDesc('current_total_amount')->all();
$entrantsObject = [];
foreach ($entrants as $entrant) {
$user = $entrant->user;
$entrantsObject[] = [
'entrant' => $entrant,
'user' => $user
];
}
$challengesObject[] = [
'challenge' => $challenge,
'entrants' => $entrantsObject
];
}
return $challengesObject;
}
I feel like I followed what the documentation recommended: https://laravel.com/docs/5.5/eloquent-relationships#eager-loading
but not to sure how to check to make sure I'm not making N+1 queries opposed to just 2. Any tips or suggestions to the code are welcome, along with methods to check that eager loading is working correctly.
Use Laravel Debugbar to check queries your Laravel application is creating for each request.
Your Eloquent query should generate just 3 raw SQL queries and you need to make sure this line doesn't generate N additional queries:
$entrants = $challenge->entrants->load('user')->sortByDesc('current_total_amount')->all()
when you do ->with('entrants.user') it loads both the entrants and the user once you get to ->get(). When you do ->load('user') it runs another query to get the user. but you don't need to do this since you already pulled it when you ran ->with('entrants.user').
If you use ->loadMissing('user') instead of ->load('user') it should prevent the redundant call.
But, if you leverage Collection methods you can get away with just running the 1 query at the beginning where you declared $challenges:
foreach ($challenges as $challenge) {
// at this point, $challenge->entrants is a Collection because you already eager-loaded it
$entrants = $challenge->entrants->sortByDesc('current_total_amount');
// etc...
You don't need to use ->load('user') because $challenge->entrants is already populated with entrants and the related users. so you can just leverage the Collection method ->sortByDesc() to sort the list in php.
also, You don't need to run ->all() because that would convert it into an array of models (you can keep it as a collection of models and still foreach it).

Flow3 PHP: Add item to empty collection

I searched a while, but until now, I wasn't able to find a suitable answer.
In my "Offer" class, I have the following:
/**
* #ORM\OneToMany(mappedBy="offer")
* #var Collection<OfferItem>
*/
protected $offerItems;
/**
* #return Collection
*/
public function getOfferItems()
{
return $this->offerItems;
}
/**
* #param Collection $offerItems
*/
public function setOfferItems($offerItems)
{
$this->offerItems = $offerItems;
}
Now, I create a new Offer and would like to add some OfferItems as well:
$offer = new Offer();
$offerItem = new OfferItem();
$offer->getOfferItems()->add($offerItem);
But then, the error comes: "Fatal error: Call to a member function add() on null". Okay, in some points, it makes sense - the collection is empty until know - and perhaps "null".
I'm not such an PHP / Flow3 / Doctrine expert, to have the overview, how to handle such an sitation?
I think, I have to set an empty (but not null-) collection to the offer. But
$collection = new \Doctrine\Common\Collections\Collection()
Is not working, because "Collection" is an interface.
Any hint, idea or something like that, to understand my problem would be nice.
Thank you very much in advance for your help!

Yii - Error setting Active Record dynamic table names

Hi I'm trying to use a model that will generate dynamic table name from another database. I've managed to set the table name by overriding the tableName() function. But i'm getting an error saying
The table "powerDovakin_{FUS.THUM}" for active record class "PowersTransactions" cannot be found in the database
Here is the model class in question
<?php
class PowersTransactions
extends CActiveRecord {
public $symbol ;
public function __construct ($symbol) {
$this->symbol = $symbol;
}
/**
* #return string the associated database table name
*/
public function tableName () {
return "powerDovakin_{" . $this->symbol ."}";
}
/**
* #return array relational rules.
*/
public function relations () {
// NOTE: you may need to adjust the relation name and the related
// class name for the relations automatically generated below.
return array (
) ;
}
/**
* Returns the static model of the specified AR class.
* Please note that you should have this exact method in all your CActiveRecord descendants!
* #param string $className active record class name.
* #return InsidersTransactions the static model class
*/
public static function model ( $className = __CLASS__ ) {
return parent::model ( $className ) ;
}
/**
* Overriding parent getDbConnection to allow for use of different database
*/
public function getDbConnection () {
return Yii::app ()->powersDovakin ;
}
}
Now i've turned on logging and the trace shows that the error is being thrown when this query is being executed.. Here are some of the relevant lines from the stack trace
12:19:45.053172 trace system.db.CDbConnection
[ocak07jk4q3v8nfd535io8fdd4] Opening DB connection
in /var/www/html/PowerAnalysis/protected/models/PowersTransactions.php
(283)
in /var/www/html/PowerAnalysis/protected/models/PowersTransactions.php
(191)
in /var/www/html/PowerAnalysis/protected/views/realTime/_powerView.php
(9)
12:19:45.053564 trace system.db.CDbCommand
[ocak07jk4q3v8nfd535io8fdd4] Querying SQL: SHOW FULL COLUMNS FROM
`powerDovakin_{FUS.THUM}`
in /var/www/html/PowerAnalysis/protected/models/PowersTransactions.php
(191)
in /var/www/html/PowerAnalysis/protected/views/realTime/_powerView.php
(9)
in /var/www/html/PowerAnalysis/protected/views/realTime/view.php (715)
12:19:45.053858 error system.db.CDbCommand
[ocak07jk4q3v8nfd535io8fdd4] CDbCommand::fetchAll() failed:
SQLSTATE[42000]: Syntax error or access violation: 1142 SELECT command
denied to user 'user1'#'localhost' for table 'THUM}'. The SQL statement
executed was: SHOW FULL COLUMNS FROM `powerDovakin_{FUS`.`THUM}`.
in /var/www/html/PowerAnalysis/protected/models/PowersTransactions.php
(191)
in /var/www/html/PowerAnalysis/protected/views/realTime/_powerView.php
(9)
in /var/www/html/PowerAnalysis/protected/views/realTime/view.php (715)
From the above trace what i could find out is that Yii is putting backticks (`) around the dots and maybe interpreting the portion after the dots as a column name.
My question is how can i make Yii use this sort of table names. I wish i could change the table names but my hands are tied at this moment. I just can't change them as they are not mine. So again the table names are like
powerDovakin_{FUS.THUM} , powerDovakin_{ROH.THUM}, etc
Is it possible to make the model accept such names. Please provide any sort of help as i can't find any solution to this problem. I would really appreciate any help i can get on this.
Thanks, In Advance,
Maxx
the above code might give you the ability to fetch records from the tables but i don't think that you can insert any rows.
You need to call the constructor of the parent class in order to get the required functionality.
class PowersTransactions extends CActiveRecord {
public $symbol;
public function __construct ($symbol) {
$this->symbol = $symbol;
parent::__construct();
}
/**
* other code goes here
*/
}
Code above was tested and working

Categories