Laravel AutoHydrate Ardent Model, but sometimes manually assign? - laravel-4

So I have my Model setup like this:
protected $fillable = array('dragon_id', 'name', 'gender');
public $autoHydrateEntityFromInput = true; // hydrates on new entries' validation
public $forceEntityHydrationFromInput = true; // hydrates whenever validation is called
However in ONE instance, I need to manually assign some of the attributes.. is there a way to do this? Because when I manually assign with auto hydrate set to true, it overwrites what I manually set.
Thanks for any help/suggestions!

I had the same problem, if you set public $forceEntityHydrationFromInput = false; (or comment out completely) then you can call:
$newModel = MyModelClass::create(arrayOfAttributes);
And it will not auto hydrate.

Related

Argument 1 passed to Spatie\Activitylog\ActivityLogger::performedOn() must be an instance of Illuminate\Database\Eloquent\Model, string given

I am using Spatie activity log package.
Within my controller, I am trying to pass the model name but I get the on my question's title.
See my Model below:
class Project extends Model
{
//
use SoftDeletes;
protected $softDelete = true;
protected static $logAttibutes = ['projectname','duedate','team_id','assignee_id',
,'projecttype_id'];
public static $logName = 'project';
public function getDescriptionForEvent(string $eventName): string
{
return "You have {$eventName} project" ;
}
The event logging for viewing a list happens in the controller. As shown below:
public function index()
{
//
$projects = Project::all();
activity()
->useLog('Projects')
->withProperties(['type'=>'view project list'])
->performedOn(Project::class)
->log('viewed the project list');
return view('projects.index',['projects'=>$projects]);
}
On performedOn, I also tried:
->performedOn('App/Project')
The documentation says
->performedOn($someContentModel)
This is just a variable and I know a variable needs to be populated with some data, but I think I'm struggling to understand the format of that data
Can you try this :
$project = new Project();
--
$activity()
->performedOn($project)
That means use the object of project as argument which we can also call, the instance of model.

Laravel check if updateOrCreate performed an update

I have the following code in my controller:
for($i=0; $i<$number_of_tourists; $i++) {
$tourist = Tourist::updateOrCreate([
'doc_number' => $request['doc_number'][$I]
],
$tourist_to_update);
}
Each time updateOrCreate runs, it does 1 of 3 things:
Updates the model instance; OR
Creates and saves a new one; OR
Leaves everything unchanged (if model with such values already exists)
I need to check if updateOrCreate has done the first one (updated) and then execute some code.
How can I do it?
You can figure it out like this:
$tourist = Tourist::updateOrCreate([...]);
if(!$tourist->wasRecentlyCreated && $tourist->wasChanged()){
// updateOrCreate performed an update
}
if(!$tourist->wasRecentlyCreated && !$tourist->wasChanged()){
// updateOrCreate performed nothing, row did not change
}
if($tourist->wasRecentlyCreated){
// updateOrCreate performed create
}
Remarks
From Laravel 5.5 upwards you can check if updates have actually taken place with the wasChanged and isDirty method.
isDirty() is true if model attribute has been changed and not saved.
wasChanged() is true if model attribute has been changed and saved.
There is also a property (not method!) wasRecentlyCreated to check if user was created or not.
$user = factory(\App\User::class)->create();
$user->wasRecentlyCreated; // true
$user->wasChanged(); // false
$user->isDirty(); // false
$user = \App\User::find($user->id);
$user->wasRecentlyCreated; // false
$user->wasChanged(); // false
$user->isDirty(); // false
$user->firstname = 'Max';
$user->wasChanged(); // false
$user->isDirty(); // true
$user->save();
$user->wasChanged(); // true
$user->isDirty(); // false
//You can also check if a specific attribute was changed:
$user->wasChanged('firstname');
$user->isDirty('firstname');
You can checkout the link to the laravel's documentation for wasChanged and isDirty methods.
https://laravel.com/docs/8.x/eloquent#examining-attribute-changes or
https://laravel.com/docs/9.x/eloquent#examining-attribute-changes
It is pretty easy to determine if the function resulted in an update or an insert (check the wasRecentlyCreated property). However, when using that function, it is less easy to determine if the update actually happened (if the model exists but is not dirty, no update will be performed). I would suggest not using that function, and splitting out the functionality yourself.
This is the function definition:
public function updateOrCreate(array $attributes, array $values = [])
{
$instance = $this->firstOrNew($attributes);
$instance->fill($values)->save();
return $instance;
}
To integrate this into your code, I'd suggest something like:
for ($i=0; $i<$number_of_tourists; $i++) {
$tourist = Tourist::firstOrNew(['doc_number' => $request['doc_number'][$i]]);
$tourist->fill($tourist_to_update);
// if the record exists and the fill changed data, update will be performed
$updated = $tourist->exists && $tourist->isDirty();
// save the tourist (insert or update)
$tourist->save();
if ($updated) {
// extra code
}
}
Okay so I couldn't find a good answer for my scenario.
I was using: $this->created_at == $this->updated_at however I would sometimes update the record later in the request, which meant that 20% of the time the created_at and updated_at were about 1ms out.
To combat this I created something a little more relaxed which allows an extra second between creation and modification.
public function getRecentlyCreatedAttribute()
{
return $this->wasRecentlyCreated || $this->created_at == $this->updated_at || $this->created_at->diffInSeconds($this->updated_at) <= 1;
}
I can now call $this->recentlyCreated which will return true if there is a small difference in time (1 second).
Tbh this is the second time I've needed this in a project, I'm posting as I just ended up googling it and coming back to this thread looking for the same answer.
If someone has a more elegant solution, hmu.
#patricus below presented a working way to solve the problem.
though #TheFallen here gave a solution which uses Eloquent Events and seems more elegant:
Laravel Eloquent Events - implement to save model if Updated
The model attribute 'wasRecentlyCreated' would only be 'true' if it has just been created.
There is property named 'changes' in model (it is an array), that determines whether the model has been updated with new values or it has been saved as is without making any changes to its attribute.
Check the following code snippet:
// Case 1 : Model Created
if ($model->wasRecentlyCreated) {
} else { // Case 2 : Model Updated
if (count($model->changes)) { // model has been assigned new values to one of its attributes and saved successfully
} else { // model has NOT been assigned new values to one of its attributes and saved as is
}
}

Validating length depending on a setting in CakePHP

Note that I am using CakePHP 1.3.
I would like to validate the length of several fields of a model depending on a limit defined by the administrator in the database.
I have one model called Setting through which I can fetch the maxLength values. My idea is to use the beforeValidate method to fetch them, and then set the $validate parameter accordingly :
<?php
class Mod extends AppModel
{
var $belongsTo = array('IBelong');
var $hasMany = array('IHaz');
function beforeValidate() {
// Fetch the maxLength settings : requestAction to the SettingsController ?
// Somehow do $this->Setting->find... ?
// Then set the $validate attribute
}
}
?>
What method can I use to get the maxLength values in the beforeValidate callback ?
Thanks !
Edit : following comments by Dave, here is what I am currently doing (and it works) :
<?php
class Mod extends AppModel
{
var $belongsTo = array('IBelong');
var $hasMany = array('IHaz');
function beforeValidate() {
App::import('Model', 'Setting');
$setting = new Setting();
// Use $setting->find... to fetch the settings
// Set the $validate attribute to validate using the settings
}
}
?>
However, I am still not sure if this is the right approach.
Note that I have several attributes to validate, and I would like to avoid having to call $setting->find several times for best performance.
Data Validation is very thoroughly explained in the CakePHP book.
If you read the Custom Validation Rules area, you'll see an example of them pulling data from the database to use in their validation - exactly like what you want.
(Here's Custom Validation Rules for 1.3)

How we setup cakephp without database?

In few project we don't need database, so how we setup cakephp on local machine without modification in database config? Right now what I done ...I created database and modified config file. But my database has no table, its just wastage of database....so please suggest better way to do this.
Thank you in advance..
With CakePHP 2.3.x I simply use an empty string as a datasource in the database configuration and it works fine.
The database configuration (app/Config/database.php) is almost empty, it looks like this:
class DATABASE_CONFIG {
public $default = array(
'datasource' => '',
);
}
You have to tell your AppModel not to use DB tables, otherwise you'll get an error: "Datasource class could not be found". It's not enough to set the $useTables in descendant models only.
class AppModel extends Model {
public $useTable = false;
}
I dindn't experienced any problems with that yet.
Cakephp actually try to connect to a database no matter that you don’t use a table
so using this
class MyModel extends AppModel {
public $useTable = false;
}
it will be just a mistake , creating application on cakephp is piece of cake. Here are some steps you have to do in order to start developing without a database.
Create fake dbo source
Create file DboFakeDboSource.php in app/Model/Datasource/Dbo/ and put the following code in it
class DboFakeDboSource extends DboSource {
function connect() {
$this->connected = true;
return $this->connected;
}
function disconnect() {
$this->connected = false;
return !$this->connected;
}
}
Set the default connection
The next step is to tell cakephp to use dbo source by default. Go and change default connection in database.php to be like this
var $default = array(
'driver' => 'FakeDboSource'
);
Fine tuning the model
The third step is to be sure that $useTable = false; is included in every model, so add it in AppModel.php
You can just leave default datasourse settings empty in database.php and for Models you use, specify that it doesn't need corresponding table in DB like following:
class MyModel extends AppModel {
public $useTable = false;
}

joomla set JTable property to null

How i can set JTable property too null and save it
my code so far w/o succes:
$table = JTable::getInstance($type='detalegrupy', $prefix='FootsalTable', $config = array());
$table->load($id);
$table->promotion = NULL;
$id_group = $table->id_group;
$table->store();
or how to restore it to it's default value.
i found answer for it,
$table->store(TRUE);
done the work.
sorry for spam
Edit the file administrator/components/YOUR_COMPONENT/tables/NAME_OF_YOUR_TABLE.php and add this function inside the table class:
public function store($updateNulls = true)
{
return parent::store($updateNulls);
}

Resources