Eloquent select using the wrong class? - php

Context: Trying to extend Laravel models from a database table. Table models linked to App\Models\BootableModel, App\Models\User extends this class.
I have the following code:
<?php
class BootableModel extends Model
{
protected $table = 'models';
protected $fillable = [
'name',
'class',
'table',
];
public function __construct(array $attributes = [])
{
$this->bootFromDatabase();
parent::__construct($attributes);
}
private function bootFromDatabase()
{
$class = static::class;
$bModClass = self::class;
Log::debug($class);
Log::debug($bModClass);
//$bootableModel = DB::table('models')->where('class', $class)->first();
$bootableModel = $bModClass::where('class', $class)->first();
if(!$bootableModel) {
return;
}
Log::debug($bootableModel->id);
The debug of $bModClass shows App\Models\BootableModel as expected (self vs static), but for some reason the $bModClass::where is trying to query the users table. Using a direct reference to App\Models\BootableModel::class does not change this, so it's not self::class that is the issue. The debug output as proof:
[2021-02-21 17:33:39] local.DEBUG: App\Models\User
[2021-02-21 17:33:39] local.DEBUG: App\Models\BootableModel
It should never try to access User::where(), and as such, it should never try to use User::$table either, but somehow it does.
Is Laravel doing some weird reflection, or is this normal PHP behavior? Is there a way around this?
Update:
I have found a workaround, but I'm not satisfied with this being the correct/only solution:
public function __construct(array $attributes = [])
{
parent::__construct($attributes);
static::bootFromDatabase();
}
public static function bootFromDatabase()
{
$class = static::class;
$bModClass = self::class;
if($class === $bModClass) {
return;
}

Have you ever tried self::where(...) instead of $bModClass::where(...) ?
Similar situation:
class Base {
public static function where()
{
return 'where from base';
}
public static function getName()
{
return self::where();
}
}
class User extends Base {
public static function where()
{
return 'where from user';
}
}
echo User::getName();
Output: where from base

Related

Laravel query with multiple where not returning expected result

I'm trying to build a query from a Repository in a Model with 2 where clauses.
This is the data I have in a MySql table:
id name environment_hash
1 online_debit abc
2 credit_cart abc
I want to query by name and environment_hash. To do this, I created the method findByHashAndMethod() (see below).
But when I use it in my controller, like this:
$online_debit = $this->ecommercePaymentMethodRepository->findByHashAndMethod($hash, 'online_debit')->first();
or this:
$credit_card = $this->ecommercePaymentMethodRepository->findByHashAndMethod($hash, 'credit_cart')->first();
I keep getting both rows and not only the ones filtered. What's wrong with the code?
This is my PaymentMethodRepository.php
class EcommercePaymentMethodRepository extends BaseRepository
{
public function findByHashAndMethod($hash = null, $payment_method)
{
$model = $this->model;
if($hash)
{
$filters = ['environment_hash' => $hash, 'name' => $payment_method];
$this->model->where($filters);
}
else
{
$this->model->where('environment_hash', Auth::user()->environment_hash)
->where('name', $payment_method);
}
return $model;
}
public function model()
{
return EcommercePaymentMethod::class;
}
}
And this is my model EcommercePaymentMethod.php
<?php
namespace App\Models;
use Eloquent as Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class EcommercePaymentMethod extends Model
{
use SoftDeletes;
public $table = "ecommerce_payment_methods";
protected $dates = ['deleted_at'];
public $fillable = [
"name",
"payment_processor_id",
"active",
"environment_hash"
];
protected $casts = [
"name" => "string"
];
public function payment_processor()
{
return $this->hasOne('App\Models\EcommercePaymentProcessor');
}
}
While I am not entirely sure why ->first() would ever return more than one result, your Repository method had some few glaring issues that's prone to errors.
class EcommercePaymentMethodRepository extends BaseRepository
{
// 1. Do not put optional parameter BEFORE non-optional
public function findByHashAndMethod($payment_method, $hash = null)
{
// 2. Call ->model() method
$model = new $this->model();
// 3. Logic cleanup
if (is_null($hash)) {
$hash = Auth::user()->environment_hash;
}
return $model->where('environment_hash', $hash)
->where('name', $payment_method);
}
public function model()
{
return EcommercePaymentMethod::class;
}
}

Laravel return Illegal offset type when I trie return a model

I'm working with a large json that returns several data from the database and I need to return an integer model that does not have any kind of relationship, I just need to return all the records that LampModels model with this great json. But Laravel always returns me Illegal offset type.
Controller
public function showAllUdiJson()
{
$allLamps = LampModels::all();
return Ilumination::with('street')
->with('neighborhood')
->with('iluminationinfo')
->with('economyplan')
->with('lamp')
->with('reactor')
->with('aluminumcable')
->with('steelconduit')
->with('alllamps', $allLamps)
->with('ticket')->get();
}
LampModels
<?php
class LampModels extends \Eloquent {
protected $fillable = [];
protected $table = 'lampmodel';
}
Illumination
<?php
class Ilumination extends \Eloquent {
protected $fillable = [];
protected $table = 'ilumination';
public function street()
{
return $this->belongsTo('street');
}
public function neighborhood()
{
return $this->hasOne('neighborhood', 'id');
}
public function iluminationinfo()
{
return $this->hasOne('iluminationinfo');
}
public function ticket()
{
return $this->hasMany('ticket');
}
public function economyplan()
{
return $this->hasOne('economyplan', 'id' ,'street_id');
}
public function lamp()
{
return $this->hasOne('lamp', 'id');
}
public function reactor()
{
return $this->hasOne('reactor', 'id');
}
public function aluminumcable()
{
return $this->hasOne('aluminumcable', 'id');
}
public function steelconduit()
{
return $this->hasOne('steelconduit', 'id');
}
}
See the error
Your error report is quite bad, but seems that your Ilumination model doesnt have an alllamps method.
You should attacth LampModels to your Ilumination model with a relationship, insted of doing what you doing, cause is a wrong approach.
I think you access somewhere ticket method which was created in Illumination Model that offset error encountered..
public function ticket()
{
return $this->hasMany('ticket');
}
if you want to access illumination->ticket, you must use this method with loop.
foreach(illumination->tickets as ticket) {
$field1 = ticket->field1;
}
If your still facing any issue than share your error log page here..

Model Observer, not working for update?

Im having trouble trying to get my model observer to work.. It is working as expected for create and deleted, but not for updating. Im guessing the event never fires. The thing is all of then are being done exactly the same way. Any ideas?
Below, my observer.
class GenericObserver extends AbstractObserver {
protected $events;
public function __construct(Dispatcher $dispatcher){
$this->events = $dispatcher;
}
public function saved($model) {
dd($this->events);
$user_id = Auth::user()->usr_id;
$user_nome = Auth::user()->usr_nome;
$user_email = Auth::user()->usr_email;
dd($model);
}
public function deleted($model) {
$user_id = Auth::user()->usr_id;
$user_nome = Auth::user()->usr_nome;
$user_email = Auth::user()->usr_email;
echo($model->getTable());
dd($model->getKeyName());
}
public function updated($model) {
$user_id = Auth::user()->usr_id;
$user_nome = Auth::user()->usr_nome;
$user_email = Auth::user()->usr_email;
dd($model);
}
public function saving($model){
echo 'Saving';
}
public function deleting($model){
echo 'Deleting';
}
public function updating($model){
echo 'Updating';
}
And here, my model class
Aplicacao extends Model {
protected $table = 'gst_aplicacoes';
protected $primaryKey = 'app_id';
protected $fillable = ['app_nome', 'app_key', 'app_observacao'];
public static function table() {
$model = new static;
return $model->getTable();
}
public static function boot() {
parent::boot();
Aplicacao::observe(new GenericObserver(new Dispatcher));
}
If anyone ever faces this issue, the reason the event was not firing was because the update method, only fire its events when the update happens directly on the model, since i was using an intermediary repository to represent my model, it wasn't working.
for more details.
https://github.com/laravel/framework/issues/11777#issuecomment-170388067
Observer work on only save() method. And it's not working on function of query builder that you call by magic methods. So on update() and created() observer is not work.
This will work:
Model::find($id)->update(['column' => $value]);

How to call a function inside eloquent Model directly without query?

I have function showItemList inside User class
class User extends Eloquent {
//...
protected $item = ['axe', 'sword', 'knife'];
public function showItemList() {
return $this->$item;
}
}
In my controller it's possible to use this.
$id = 1;
$user = User::find($id);
$user -> showItemList();
But how can I just call this function directly(irrelevant to $id query)?
I looks for something like below (sure now it's not working):
$list = User::showItemList();
You need to use the static protected variable and return it from static method.
class User extends Eloquent {
//...
static protected $item = ['axe', 'sword', 'knife'];
public static function showItemList() {
return self::$item;
}
}

accessing object and its relations in laravel 4.1

I hope I can explain this clearly, apologies in advance if it is confusing. I have a goals table which hasOne of each of bodyGoalDescs, strengthGoalDescs and distanceGoalDescs as shown below
goals.php
class Goal extends BaseModel
{
protected $guarded = array();
public static $rules = array();
//define relationships
public function user()
{
return $this->belongsTo('User', 'id', 'userId');
}
public function goalStatus()
{
return $this->hasOne('GoalStatus', 'id', 'goalStatus');
}
public function bodyGoalDesc()
{
return $this->hasOne('BodyGoalDesc', 'id', 'bodyGoalId');
}
public function distanceGoalDesc()
{
return $this->hasOne('DistanceGoalDesc', 'id', 'distanceGoalId');
}
public function strengthGoalDesc()
{
return $this->hasOne('StrengthGoalDesc', 'id', 'strengthGoalId');
}
//goal specific functions
public static function yourGoals()
{
return static::where('userId', '=', Auth::user()->id)->paginate();
}
}
each of the three tables looks like this with the function details changed
class BodyGoalDesc extends BaseModel
{
protected $guarded = array();
public static $rules = array();
/**
* The database table used by the model.
*
* #var string
*/
protected $table = 'bodyGoalDescs';
//define relationships
public function goal()
{
return $this->belongsTo('Goal', 'bodyGoalId', 'id');
}
}
a goal has either a body goal, a strength goal, or a distance goal. I am having a problem with this method in the controller function
<?php
class GoalsController extends BaseController
{
protected $goal;
public function __construct(Goal $goal)
{
$this->goal = $goal;
}
/**
* Display the specified resource.
*
* #param int $id
* #return Response
*/
public function show($id)
{
$thisgoal = $this->goal->find($id);
foreach ($this->goal->with('distanceGoalDesc')->get() as $distancegoaldesc) {
dd($distancegoaldesc->DistanceGoalDesc);
}
}
}
when I pass through goal 1 which has a distance goal the above method dies and dumps the Goal object with the details of goal 1 and an array of its relations including an object with DistanceGoalDes.
when I pass through goal 2 it passes through exactly the same as if I had passed through goal 1
if I dd() $thisgoal i get the goal that was passed through
what I want ultimately is a method that returns the goal object with its relevant goal description object to the view but this wont even show me the correct goal details not too mind with the correct relations
this function is now doing what I want it to do, I am sure there is a better way (besides the fact that its happening in the controller right now) and I would love to hear it.
public function show($id)
{
$thisgoal = $this->goal->find($id);
if (!$thisgoal->bodyGoalDesc == null) {
$goaldesc = $thisgoal->bodyGoalDesc;
return View::make('goals.show')
->with('goal', $thisgoal)
->with('bodygoaldesc', $goaldesc);
} elseif (!$thisgoal->strengthGoalDesc == null) {
$goaldesc = $thisgoal->strengthGoalDesc;
return View::make('goals.show')
->with('goal', $thisgoal)
->with('strengthgoaldesc', $goaldesc);
} elseif (!$thisgoal->distanceGoalDesc == null) {
$goaldesc = $thisgoal->distanceGoalDesc;
return View::make('goals.show')
->with('goal', $thisgoal)
->with('distancegoaldesc', $goaldesc);
}
}

Categories