I'm trying to force my application to use the write connection when running a select because of race conditions dealing with updating the data and refreshing it. I have confirmed that useWritePdo() function is being called, but I can tell it's not using the write connection because the race condition bug still exists. I don't know how to determine through var dumps whether the write connection is being used.
Here is the code I'm running, followed by the involved models. Note that forcing the write connection works if I call $portfolio->items($useWriteConn), but not $user->portfolios($useWriteConn)->with('items').
return $this->user->portfolios($useWriteConn)->with('items')->find($id);
Model User.php:
namespace App;
use App\Notifications\ResetPassword;
use App\Support\Auth\RetrievesUser;
use Illuminate\Auth\Authenticatable;
use Illuminate\Auth\Passwords\CanResetPassword;
use Illuminate\Contracts\Auth\Access\Authorizable as AuthorizableContract;
use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Foundation\Auth\Access\Authorizable;
use Illuminate\Notifications\Notifiable;
use Laravel\Passport\HasApiTokens;
/**
* Class User
* #package App
* #property integer $subscription
* #property integer $id
*/
class User extends Model implements AuthenticatableContract,
AuthorizableContract,
CanResetPasswordContract
{
use Authenticatable, Authorizable, CanResetPassword, UserTrait, Notifiable, HasApiTokens, RetrievesUser
public function portfolios($useWriteConn = false)
{
return ($useWriteConn)
? $this->hasMany(UserPortfolio::class, 'user')->writeConn()
: $this->hasMany(UserPortfolio::class, 'user');
}
}
Model UserPortfolio.php
namespace App;
// use App\UserCustomViews;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\SoftDeletes;
class UserPortfolio extends Model
{
use SoftDeletes;
public function user()
{
return $this->belongsTo(User::class, 'user');
}
public function items($useWriteConn = false, $showClosed = true)
{
$items = $this->hasMany(UserPortfolioItem::class, 'portfolio');
if ($useWriteConn)
$items->writeConn();
if (!$showClosed)
$items->open();
return $items;
}
public function scopeWriteConn($query)
{
return $query->useWritePdo();
}
}
Model UserPortfolioItem.php
namespace App;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\SoftDeletes;
class UserPortfolioItem extends Model
{
public function portfolio()
{
return $this->belongsTo(UserPortfolio::class, 'portfolio');
}
public function scopeWriteConn($query)
{
return $query->useWritePdo();
}
}
For anyone who comes across this later, I found the answer in another thread.
Eloquent pre-loading relationships against DB write connection
Model::onWriteConnection()->with(['relationship'=>function($query){
$query->useWritePdo();
}])->find($id)
Related
I have 3 tables:
subdistrict (in database B)
users (in database A)
admin_area (in database A).
and now, i want to insert or display data for user with area. below is the code i have made:
Model User
<?php
namespace App\Models;
use App\Models\Marketplace\Subdistrict;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Illuminate\Support\Facades\DB;
use Laravel\Sanctum\HasApiTokens;
use Spatie\Permission\Traits\HasRoles;
class User extends Authenticatable
{
use HasApiTokens, HasFactory, Notifiable, HasRoles, SoftDeletes;
public function areas()
{
return $this->belongsToMany(Subdistrict::class, 'admin_area', 'user_id', 'subdistrict_id');
}
}
Model Subdistrict
<?php
namespace App\Models\Marketplace;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Subdistrict extends Model
{
use HasFactory;
protected $connection = 'marketplace';
protected $table = 'subdistrict';
public function users() {
return $this->belongsToMany(User::class, 'admin_area', 'user_id', 'subdistrict_id');
}
}
admin_area table:
user_id
subdistrict_id
If I try to get the areas from user_id = 1, I get an error like below
How to fix it? or How to make pivot table with different database in laravel 8?
Barring any design considerations, you can try by including the database name in front of the table. I'm assuming that the databases are in the same server.
Try alternating database_a or database_b (I'm not 100% clear on how the relationship was created).
class User extends Authenticatable
{
use HasApiTokens, HasFactory, Notifiable, HasRoles, SoftDeletes;
public function areas()
{
return $this->belongsToMany(Subdistrict::class, 'database_a.admin_area', 'user_id', 'subdistrict_id');
}
}
AuthController.php
namespace App\Http\Controllers;
use App\Mail\VerifyMail;
use App\Models\User;
use App\Models\VerifyUser;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Mail;
class AuthController extends Controller
{
//
}
VerifyUser
<?php
namespace App\Models\User;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class VerifyUser extends Model
{
use HasFactory;
protected $guarded = [];
public function user()
{
return $this->belongsTo('App\User', 'user_id');
}
}
The application is made with Laravel 8
do you have any idea what i'm doing wrong ? i get Error Class "App\Models\VerifyUser" not found in AuthController
I wanna try to make test, member who logged in can create a job, this is my test code.
/** #test */
public function member_can_create_a_job(){
$member = factory('App\Models\M_member')->create();
$this->actingAs($member);
$job = factory('App\Models\M_lowker')->make();
$this->post('/lowker/tambah-lowker', $job->toArray())->assertRedirect('/lowker/tambah-lowker');
}
This is my App\Models\M_member
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class M_member extends Model{
protected $table = "member";
public $timestamps = false;
protected $fillable = ["nama", "email", "password", "alamat", "tgl_lahir", "remember_token"];
public function jobs()
{
return $this->hasMany('App\Models\M_lowker');
}
public function comments()
{
return $this->hasMany('App\Models\M_komentar');
}
}
When I run, I get error in cmd like
this.
1) Tests\Feature\JPSTest::member_can_create_a_job TypeError: Argument 1 passed to Illuminate\Foundation\Testing\TestCase::actingAs() must be an instance of Illuminate\Contracts\Auth\Authenticatable, instance of App\Models\M_member given, called in I:\W 42 N\Home Work\Semester 5\Rekayasa Perangkat Lunak\Praktikum\jps\tests\Feature\JPSTest.php on line 35
I:\W 42 N\Home Work\Semester 5\Rekayasa Perangkat Lunak\Praktikum\jps\vendor\laravel\framework\src\Illuminate\Foundation\Testing\Concerns\InteractsWithAuthentication.php:16 I:\W 42 N\Home Work\Semester 5\Rekayasa Perangkat Lunak\Praktikum\jps\tests\Feature\JPSTest.php:35
ERRORS! Tests: 3, Assertions: 3, Errors: 1.
This error tells you that the model which you are using is not extending the Illuminate\Contracts\Auth\Authenticatable contract, which is necessary to use the actingAs method. If you have laravel's auth you can check the user model as an example of this . Which is something like:
<?php
namespace App;
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable
{
So, try extending your model to have this functionality.
or you can implement the Authenticatable contract on your model like this
class User extends Model implements
AuthenticatableContract,
AuthorizableContract,
CanResetPasswordContract
{
use Authenticatable, Authorizable, CanResetPassword;
}
You can add first() when you create user
$user = factory('App\User')->create()->first();
This problem solved with modify my M_member model like this.
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Auth\Authenticatable as AuthenticableTrait;
class M_member extends Model implements Authenticatable{
use AuthenticableTrait;
I am doing an ajax login in my Laravel application. It worked fine on my local environment, but I moved the site to Production, on login I see this exception
ErrorException in User.php line 29: Illuminate\Foundation\Auth\User
and Illuminate\Auth\Authenticatable define the same property
($rememberTokenName) in the composition of App\User. This might be
incompatible, to improve maintainability consider using accessor
methods in traits instead. Class was composed
My User model is as
<?php
namespace App;
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable
{
use Notifiable, \Illuminate\Auth\Authenticatable;
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
'name', 'email', 'password', 'first_name', 'last_name', 'hospital_id', 'census_id', 'employee_id'
];
/**
* The attributes that should be hidden for arrays.
*
* #var array
*/
protected $hidden = [
'password', 'remember_token',
];
}
Illuminate\Foundation\Auth\User already uses use Illuminate\Contracts\Auth\Authenticatable, so you basically applying the trait twice which causes that error.
Here's the code to Illuminate\Foundation\Auth\User.php
<?php
namespace Illuminate\Foundation\Auth;
use Illuminate\Auth\Authenticatable;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Auth\Passwords\CanResetPassword;
use Illuminate\Foundation\Auth\Access\Authorizable;
use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
use Illuminate\Contracts\Auth\Access\Authorizable as AuthorizableContract;
use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
class User extends Model implements
AuthenticatableContract,
AuthorizableContract,
CanResetPasswordContract
{
use Authenticatable, Authorizable, CanResetPassword;
}
Also a side suggestion rename your alias bit as Authenticable maybe to something more clear like AuthUser / BaseUser so it's clear you are extending a User class.
I have a collection controller
looks like this
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use App\Http\Requests;
use App\Http\Controllers\Controller;
use App\Http\Middleware\Role;
use Illuminate\Support\Facades\Input;
use App\User;
use App\Invoice;
use Session;
use Validator;
class CollectionController extends Controller
{
/**
* Display a listing of the resource.
*
* #return Response
*/
public function __construct(){
$this->middleware('role:collector'); // replace 'collector' with whatever role you need.
}
public function getPayment($invoiceid){
$id =$invoiceid;
$invoice=Invoice::where('Id', $id)->with(['payments'])->get();
return View('collectionmodule/payment')->with(array('invoice'=>$invoice));
}
}
Then I have following models
Invoice
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Invoice extends Model
{
//
protected $table = 'event_invoice';
public function payments(){
return $this->hasMany('App\paymentrecieved','invoice_id');
}
public function comments(){
return $this->hasMany('App\comments','invoice_id');
}
}
Paymentrecieved
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class paymentrecieved extends Model
{
//
protected $table = 'paymentrecieved';
public function invoice(){
return $this->belongsTo('App\Invoice');
}
}
So for every Invoice there could be multiple payments .
So in My getPayment method I am writing Query like this .
$invoice=Invoice::where('Id', $id)->with(['payments'])->get();
Its getting me the Details from Invoice table . But its not getting me any Payment Details
Any one know why is this happening , According to me I have done the relationship properly
Thanks
You use Id (with uppercase) for the primary key, but the Invoice model is looking for the id (with lowercase).
You should define the primary key in the Invoice model like this:
protected $primaryKey = 'Id';