laravel mutator that creates a unique random number does not run - php

I have a Question model like this:
class Question extends Model
{
use SoftDeletes;
protected $primaryKey = 'question_id';
protected $dates = ['deleted_at'];
protected $fillable = ['text', 'code', 'cat', 'answer', 'is_private', 'email', 'parent'];
public function setCodeAttribute ($value)
{
\Debugbar::info('hello');
do {
$code = rand(10000, 10000000);
$user_code = User::where('code', $code)->get();
} while (!$user_code->isEmpty());
return $this->attributes['code'] = $code;
}
}
I want to generate a random integer number and store that in code field on creation of a new instance of the model.
For that I wrote a mutator as you can see but it did not even run.
What is problem?

Well mutator itself do not run untill you don't call $question->code = $someValue.
What you need is observer and define saving method in it that will provide setting of the code attribute value in it like this:
public function saving (Operation $operation)
{
\Debugbar::info('hello');
do {
$code = rand(10000, 10000000);
$user_code = User::where('code', $code)->get();
} while (!$user_code->isEmpty());
return $operation->code = $code;
}
and of corse you need to delete the mutator from the model class as well.

Related

PHP LARAVEL Update with save() doesn't work sometimes

I have a strange problem. I'm trying to update a database entry with the save function, but the changed columns only update sometimes but most times they do not change yet I don't get any errors.
This is the code in my update function:
public function editadvocatedetails(Request $request){
try {
##get original data
$oldclaimantdets = Clthirdparties::where('claimant_code',$request->claimant_code)->first();
// ##get new data
$claimant_dets = Clthirdparties::where('record_type',$oldclaimantdets->record_type)->where('code',$oldclaimantdets->code)->first();
$claimant_dets->name = $request->name;
$claimant_dets->record_type = $request->record_type;
$claimant_dets->claimant_type = $request->claimant_type;
$claimant_dets->e_mail=$request->e_mail;
$claimant_dets->id_no=$request->id_no;
$claimant_dets->pin_number = $request->pin_number;
$claimant_dets->mobile = $request->mobile;
// // dd($claimant_dets);
$claimant_dets->save();
// dd($claimant_dets);
$mm = $claimant_dets->getChanges();
$user = Auth::user()->user_name;
$process = 'Update Claimant Details';
$claimant_code = $request->claimant_code;
$yy = $this->log_data($mm,$claimant_dets,$user,$process,$claimant_code);
Session::flash('success,'.$request->name.' details has been updated');
return redirect()->back();
} catch (\Throwable $th) {
Session::flash('error,'.$request->name.' failed to be updated');
return redirect()->back();
}
}
My Model:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Clthirdparties extends Model
{
protected $connection = 'oracle';
protected $table='clthirdparties';
public $timestamps=false;
public $keyType = 'string';
public $primaryKey='claimant_code';
public $incrementing=false;
protected $guarded = [];
}
When I print the values before the save, I get the correct values for both the old and new data.
It looks like the save() doesn't execute. The redirect is executed.
I'm aware of the update() method, but I used this way for updating entries in my database a lot and until now I never had any problems and I don't get where the problem is.
In the meantime I have reverted to update() to run the update query to solve the problem. But I still want to know why it is happening?
Maybe someone has an idea?
Sometimes hmm..., save() method is formally dependent on $fillable attribute array in the model. So, try defining fillable attributes.
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Clthirdparties extends Model
{
protected $connection = 'oracle';
protected $table='clthirdparties';
public $timestamps=false;
public $keyType = 'string';
public $primaryKey='claimant_code';
public $incrementing=false;
protected $guarded = [];
protected $fillable = ['name','record_type','claimant_type','e_mail','id_no','pin_number','mobile',] ; //include all your attributes here.
}

laravel eloquent foreach loop error Trying to get property 'location_id' of non-object

This one has happened to me before but I have no idea why and how to avoid it. So I have a static function in a Model which gets all the database rows and uses a foreach loop to read another table but I am unable to correctly read the row data:
public static function test()
{
$accounts = self::where( 'is_enabled', 1 )->get();
foreach ( $accounts as $account ) {
$map = AccountMap::where( 'account_id', $account->id )->first();
$location = Location::getLocation( $map->location_id );
$data = $location->getData();
}
}
So the above function gathers an array of items ($accounts) this is then passed into a foreach loop all is fine to this point but if i now use $account->id it is null. The id is shown in the Account object in its attributes folder.
A very similar function is used elsewhere in this model but it uses a passed id and this one works (however $account->id is null). The issue is not the database or column names:
public static function getThisLocation( $id )
{
$account = self::find( $id );
$map = AccountMap::where( 'account_id', $id )->first();
location = Location::getLocation( $map->location_id );
$data = $location->getData();
return $data;
}
*** EDIT ***
Account, AccountMap and Location are all Eloquent models
namespace App\Models;
use Eloquent;
use App\Notifications\AccountMessages;
use Kyslik\ColumnSortable\Sortable;
use Illuminate\Notifications\Notifiable;
/**
* #method static find(int $id)
*/
class Account extends Eloquent
{
use Sortable;
use Notifiable;
public $sortable = [
'id',
'name',
'lastupdate',
'url'
];
public static function test()
{
$accounts = self::where( 'is_enabled', 1 )->get();
foreach ( $accounts as $account ) {
$map = AccountMap::where( 'account_id', $account->id )->first();
$location = Location::getLocation( $map->location_id );
$data = $location->getData();
}
}
public static function getThisLocation( $id )
{
$account = self::find( $id );
$map = AccountMap::where( 'account_id', $id )->first();
location = Location::getLocation( $map->location_id );
$data = $location->getData();
return $data;
}
}
namespace App\Models;
use Eloquent;
use Kyslik\ColumnSortable\Sortable;
/**
* #method static where(string $string, int $id)
*/
class AccountMap extends Eloquent
{
use Sortable;
public $sortable = [
'id',
'account_id',
'location'
];
}
*** MORE EDIT ***
I have confirmed that using $account->attributes['id'] has worked but I've no idea why what I expected to work didn't ($account->id)
The problem must be something related to communication of your model and migration.
Add this dd() to your current test function:
public static function test()
{
$accounts = self::where( 'is_enabled', 1 )->get();
foreach ( $accounts as $account ) {
if ($account->id){
$map = AccountMap::where( 'account_id', $account->id )->first();
$location = Location::getLocation( $map->location_id );
$data = $location->getData();
} else {
dd($account)
}
}
}
Then Check the result and see is there the id filed on your response? If not, The id field doesn't exist on your self Model and it's Your problem's cause.
Finally, Check your model fields easily with :
public function testReturnOfSelfModel()
{
$data= self::all();
dd($data);
}
If you have id on this dd function, Your Model working properly. If not, you dont have id field.
Also, it is more professional to change Capitalize your model's first charachter. It sholud be Self, not self.
I'd suggest to setup two proper data Model (a migration would need to create these tables):
class Account extends Model {
protected $table = 'accounts';
public $timestamps = false;
/**
* The attributes that are mass assignable.
* #var array
*/
protected $fillable = [];
/**
* The attributes that should be hidden for arrays.
* #var array
*/
protected $hidden = [];
}
Unless defining protected $table it will definitely not know what to do.
It's rather unclear what you're even trying to accomplish with AcountMap, but it may need a relation defined; which eg. with return $this->belongsTo(Account::class); ...while simply adding lat & lng to class Account would be far less complex and perfectly fine, while it's only 1 location.

Eloquent: guard ID when inserting into one database but don't guard it for another database.

I need to guard the ID column when inserting into a database, however I don't want to guard it when inserting into a different database due to needing to manually set the ID, so that the tables are in sync.
However I can't figure out a way to do it, below is what I have got at the moment, however this doesn't work at all as I just get an error:
Field 'id' doesn't have a default value
This is my current model:
<?php
namespace App\Models\Seasonal;
use Illuminate\Database\Eloquent\Model;
class SeasonalBanner extends Model
{
protected $connection = 'dev';
protected $guarded = [ 'id' ];
protected $appends = [ 'period' ];
public static function boot()
{
parent::boot();
self::creating(function($model){
if ($model->connection === 'live') {
$model->guarded = [];
}
});
}
public function dates() {
return $this->hasMany(SeasonalBannerDates::class);
}
public function getPeriodAttribute() {
return [ $this->start, $this->end ];
}
}
The best way in my opinion is not to use $guarded at all in such case. Just set:
protected $guarded = [];
and in your code depending on which database you use, either fill id or not.

updateOrCreate cause ErrorException in laravel

I wrote a code to login or register users.I used updateOrCreate function to add user if not exist an update a column that is name is verifcode if user exist
controller
users Table:
id(auto increment primary key)|phone|verifcode|timeStmp
---------------------------------
$phone=Input::get('phone');
$code=rand(1001,9999);
$user = new user;
$user = array('phone'=>$phone);
user::updateOrCreate($user,['verifcode' => $code]);
Model:
namespace App;
use Illuminate\Database\Eloquent\Model;
class user extends Model
{
protected $table = 'users';
protected $fillable = array('phone', 'verifcode','timeStmp');
protected $guarded = array('id');
protected $primaryKey = "id";
public $incrementing = false;
const CREATED_AT= false;
const UPDATED_AT = false;
}
with this code i have folowing error:
array_key_exists(): The first argument should be either a string or an integer that point to vendor\laravel\framework\src\Illuminate\Database\Eloquent\Concerns\HasAttributes.php file.
i just know that error point to secound argument of UpdateOrCreate function.
thanks for help
If you see at the Model class of laravel framework code, you can note, that updated_at is stored only when it is not dirty.
if (! $this->isDirty(static::UPDATED_AT)) {
$this->setUpdatedAt($time);
}
But isDirty method checks for nulls only.
public function isDirty($attributes = null)
{
$dirty = $this->getDirty();
if (is_null($attributes)) {
return count($dirty) > 0;
}
if (! is_array($attributes)) {
$attributes = func_get_args();
}
foreach ($attributes as $attribute) {
if (array_key_exists($attribute, $dirty)) {
return true;
}
}
return false;
}
So just substitute false with NULL.
If you take a look at the Laravel documentation, you're just using the updateOrCreate method wrong. Look at the flight example there.
In your case it should look like this:
$phone = \Input::get('phone')
$code = rand(1001, 9999);
$user = User::updateOrCreate(
['phone' => $phone],
['verifcode' => $code, 'timeStmp' => \Carbon::now()->timestamp]
);
finally i solve it. by adding Created_at and Update_at columns to table and adding this two coulmn to $guarded in model like this protected $guarded = array('id','CREATED_AT','UPDATED_AT'); and then problem fixed
thanks for help
$phone=Input::get('phone');
$code=rand(1001,9999);
user::updateOrCreate(
['phone' => $phone]
['verifcode' => $code]
);
See if it is work for you.

Make Trait protected attributes accessible to Eloquent in Laravel 4.2

I'm new to using Traits and having trouble saving the protected attributes of my trait within my eloquent model:
Here is my Route model:
namespace App\Models;
use Eloquent;
class Route extends Eloquent {
use CardTrait {
CardTrait::__construct as __CardConstruct;
}
public $timestamps = false;
protected $table = 'routes';
protected $primaryKey = 'id';
protected $visible = [
'name',
'description'
];
public function __construct(array $attributes = array())
{
$this->__CardConstruct($attributes);
}
//relationships follow
}
and here is the CardTrait trait:
namespace App\Models;
trait CardTrait {
protected $timesAsked;
protected $factor;
protected $nextTime;
public function __construct($attributes = array(), $timesAsked = 0, $factor = 2.5, $nextTime = null)
{
parent::__construct($attributes);
if (is_null($nextTime)) $nextTime = \Carbon::now()->toDateTimeString();
$this->factor = $factor;
$this->nextTime = $nextTime;
$this->timesAsked = $timesAsked;
public function answer($difficulty)
{
if($difficulty < 3)
$this->timesAsked = 1;
}
//other methods follow
}
In my controller I can use:
$route = new Route();
$route->name = "New Name";
$route->description = "New Description";
$route->answer(5);
$route->save();
name and description save fine, and although I have columns for timesAsked, factor and nextTime When I dd($route) I can see
protected 'timesAsked' => int 1
protected 'factor' => float 2.6
protected 'nextTime' => string '2015-04-15 21:36:53' (length=19)
so I know the methods of the Trait are working fine.
My question is how can I save these values with Eloquent so that these can be stored and retrieved from the database?
Thanks in advance.
Eloquent will store values in an internal attributes array. This is what is actually written to the database. It will not write values to the attributes array if they already exist as a data member on the model. Look into the __set and __get magic methods and how they are used in Illuminate/Database/Eloquent/Model
So long story short, remove the protected data members from the model.

Categories