i have problem with save data laravel 8 have - php

i make this query
public function scopeSelection($query){
return $query -> select('abbr', 'name', 'direction', 'active');
}
and this function for save data but nothing save in my database
public function store(LanguageRequest $request)
{
try {
Language::created($request->except(['_token']));
return redirect()->route('admin.languages')->with(['success' => 'success']);
} catch (\Exception $ex) {
return redirect()->route('admin.languages')->with(['error' => 'error']);
}
}

To insert a new record into the database, you should instantiate a new model instance and set attributes on the model. Then, call the save method on the model instance:
$language = new Language();
$language->iso = $request->iso;
$language->save();
In this example, we assign the iso field from the incoming HTTP request to the iso attribute of the App\Models\Language model instance. When we call the save method, a record will be inserted into the database. The model's created_at and updated_at timestamps will automatically be set when the save method is called, so there is no need to set them manually.
Alternatively, you may use the create method (not created) to "save" a new model using a single PHP statement. The inserted model instance will be returned to you by the create method:
use App\Models\Language;
$language= Language::create([
'iso' => 'enGB',
]);
However, before using the create method, you will need to specify either a fillable or guarded property on your model class. These properties are required because all Eloquent models are protected against mass assignment vulnerabilities by default. To learn more about mass assignment, please consult the mass assignment documentation.

Related

laravel model mutators not accessing the defined field

I am trying to define a model mutator
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Custom_fields extends Model
{
protected $table = 'custom_fields';
public function setContentAttribute($value){
return unserialize($value);
}
}
and on test controller, tried
Custom_fields::all()[0]->content;
Unfortunately, it is not working; the value is still not an array (serialize)
I want to access the field content and unserialize the value of the field so I can get an array automatically on retrieve, but it's not working.
You're trying to "get an array automatically on retrieve" with a method called setContentAttribute. You are confusing accessors and mutators. As the method name implies, the mutator is called when you set the content attribute.
To create an accessor that is called when you get the content attribute:
public function getContentAttribute($value)
{
return unserialize($value);
}
Likely if this data is to be stored in a serialized form you want your mutator to look like this:
public function setContentAttribute($value)
{
$this->attributes["content"] = serialize($value);
}
But really, you should not be using these serialization functions at all. Laravel can natively convert objects to JSON for storage in a database. Simply define the property in your model's $casts property and data will be converted automatically when getting or setting the property.
protected $casts = [
"content" => "array",
];

Is there a way to manipulate inputs in Laravel Model before storing them?

In Laravel, I have used a model's create method in many controllers,
Now I need to perform strip_tags($comment) to a specific input in all those controllers before it is inserted in database with create() method like this:
Comment:create([
'comment' => $comment,
...
]);
Should I repeatedly do this in all controllers:
$comment = strip_tags($comment); // < Is it possible to do this on model's file so we don't repeat it every time?
Comment:create([
'comment' => $comment,
...
]);
Or this is something that can be achieved in the Model?
You may use model events to make checks and arrangements before saving it.
add following method to your model class;
protected static function boot()
{
parent::boot();
self::saving(function ($model) {
$model->comment = strip_tags($model->comment);
// do your pre-checks or operations.
});
}
here is a useful post to read about it
There is a way to do it directly in the model, it's called Mutators. If your column name is comment then the mutator function will be called setCommentAttribute.
public function setCommentAttribute($comment)
{
$this->attributes['comment'] = strip_tags($comment);
}
Any place where save/update is used for this model, the comment data will go through the set... function.

Null object pattern with Eloquent relations

There is often the case where an certain eloquent model's relation is unset (i.e. in a books table, author_id is null) and thus calling something like $model->relation returns null.
E.g. say a Book model has an author() (hasOne) relation I might want to do
$author = Book::find(1)->author->name;
If Book 1 has no author set it will throw a "trying to get property of non object" error. Is there a way to avoid this and default to a blank Author so I'll always be able to call name on it regardless of whether the relation has been set for the specific model?
Essentially I want to avoid conditionals to check if $book->author is an actual Author before calling further methods/properties on it. It should default to a new Author instance if the relation isn't set.
I tried something like:
public function getAuthorAttribute($author)
{
return $author ?: new Author;
}
however this doesn't work; $author is being passed in as null, even if it's set on the model. Presumably because it's a relation rather than a direct property of a book. I'd need something like
public function getAuthorAttribute()
{
return $this->author()->first() ?: new Author;
}
which seems pretty inelegant and seems like it would override any eager loading resulting in poor performance.
Update
As of Laravel 5.3.23, there is now a built in way to accomplish this (at least for HasOne relationships). A withDefault() method was added to the HasOne relationship. In the case of your Book/Author example, your code would look like:
public function author() {
return $this->hasOne(Author::class)->withDefault();
}
This relationship will now return a fairly empty (keys are set) Author model if no record is found in the database. Additionally, you can pass in an array of attributes if you'd like to populate your empty model with some extra data, or you can pass in a Closure that returns what you'd like to have your default set to (doesn't have to be an Author model).
Until this makes it into the documentation one day, for more information you can check out the pull requests related to the change: 16198 and 16382.
At the time of this writing, this has only been implemented for the HasOne relationship. It may eventually migrate to the BelongsTo, MorphOne, and MorphTo relationships, but I can't say for sure.
Original
There's no built in way that I know of to do this, but there are a couple workarounds.
Using an Accessor
The problem with using an accessor, as you've found out, is that the $value passed to the accessor will always be null, since it is populated from the array of attributes on the model. This array of attributes does not include relationships, whether they're already loaded or not.
If you want to attempt to solve this with an accessor, you would just ignore whatever value is passed in, and check the relationship yourself.
public function getAuthorAttribute($value)
{
$key = 'author';
/**
* If the relationship is already loaded, get the value. Otherwise, attempt
* to load the value from the relationship method. This will also set the
* key in $this->relations so that subsequent calls will find the key.
*/
if (array_key_exists($key, $this->relations)) {
$value = $this->relations[$key];
} elseif (method_exists($this, $key)) {
$value = $this->getRelationshipFromMethod($key);
}
$value = $value ?: new Author();
/**
* This line is optional. Do you want to set the relationship value to be
* the new Author, or do you want to keep it null? Think of what you'd
* want in your toArray/toJson output...
*/
$this->setRelation($key, $value);
return $value;
}
Now, the problem with doing this in the accessor is that you need to define an accessor for every hasOne/belongsTo relationship on every model.
A second, smaller, issue is that the accessor is only used when accessing the attribute. So, for example, if you were to eager load the relationship, and then dd() or toArray/toJson the model, it would still show null for the relatioinship, instead of an empty Author.
Overriding Model Methods
A second option, instead of using attribute accessors, would be to override some methods on the Model. This solves both of the problems with using an attribute accessor.
You can create your own base Model class that extends the Laravel Model and overrides these methods, and then all of your other models will extend your base Model class, instead of Laravel's Model class.
To handle eager loaded relationships, you would need to override the setRelation() method. If using Laravel >= 5.2.30, this will also handle lazy loaded relationships. If using Laravel < 5.2.30, you will also need to override the getRelationshipFromMethod() method for lazy loaded relationships.
MyModel.php
class MyModel extends Model
{
/**
* Handle eager loaded relationships. Call chain:
* Model::with() => Builder::with(): sets builder eager loads
* Model::get() => Builder::get() => Builder::eagerLoadRelations() => Builder::loadRelation()
* =>Relation::initRelation() => Model::setRelation()
* =>Relation::match() =>Relation::matchOneOrMany() => Model::setRelation()
*/
public function setRelation($relation, $value)
{
/**
* Relationships to many records will always be a Collection, even when empty.
* Relationships to one record will either be a Model or null. When attempting
* to set to null, override with a new instance of the expected model.
*/
if (is_null($value)) {
// set the value to a new instance of the related model
$value = $this->$relation()->getRelated()->newInstance();
}
$this->relations[$relation] = $value;
return $this;
}
/**
* This override is only needed in Laravel < 5.2.30. In Laravel
* >= 5.2.30, this method calls the setRelation method, which
* is already overridden and contains our logic above.
*
* Handle lazy loaded relationships. Call chain:
* Model::__get() => Model::getAttribute() => Model::getRelationshipFromMethod();
*/
protected function getRelationshipFromMethod($method)
{
$results = parent::getRelationshipFromMethod($method);
/**
* Relationships to many records will always be a Collection, even when empty.
* Relationships to one record will either be a Model or null. When the
* result is null, override with a new instance of the related model.
*/
if (is_null($results)) {
$results = $this->$method()->getRelated()->newInstance();
}
return $this->relations[$method] = $results;
}
}
Book.php
class Book extends MyModel
{
//
}
I had the same problem in my project. In my views there's some rows that are accesing to dinamics properties from null relationships, but instead of returning an empty field, the app was thrwoing and exception.
I just added a foreach loop in my controller as a temporal solution that verifies in every value of the collection if the relationship is null. If this case is true, it assigns a new instance of the desire model to that value.
foreach ($shifts as $shift)
{
if (is_null($shift->productivity)) {
$shift->productivity = new Productivity();
}
}
This way when I access to $this->productivity->something in my view when the relationship is unset, I get a empty value instead of an exception without putting any logic in my views nor overriding methods.
Waiting for a better solution to do this automatically.
You can achieve this using model factories.
Define an author factory inside your ModelFactory.php
$factory->define(App\Author::class, function (Faker\Generator $faker) {
return [
'name' => $faker->firstName, //or null
'avatar' => $faker->imageUrl() //or null
];
});
add values for all the needed attributes I am using dummy values from Faker but you can use anything you want.
Then inside your book model you can return an instance of Author like this:
public function getAuthorAttribute($author)
{
return $author ?: factory(App\Author::class)->make();
}

Find or Create with Eloquent

I have recently started working with Laravel and Eloquent, and was wondering about the lack of a find or create option for models. You could always write, for example:
$user = User::find($id);
if (!$user) {
$user = new User;
}
However, is there not a better way to find or create? It seems trivial in the example, but for more complex situations it would be really helpfully to either get an existing record and update it or create a new one.
Below is the original accepted answer for: Laravel-4
There is already a method findOrFail available in Laravel and when this method is used it throws ModelNotFoundException on fail but in your case you can do it by creating a method in your model, for example, if you have a User model then you just put this function in the model
// Put this in any model and use
// Modelname::findOrCreate($id);
public static function findOrCreate($id)
{
$obj = static::find($id);
return $obj ?: new static;
}
From your controller, you can use
$user = User::findOrCreate(5);
$user->first_name = 'John';
$user->last_name = 'Doe';
$user->save();
If a user with id of 5 exists, then it'll be updated, otherwise a new user will be created but the id will be last_user_id + 1 (auto incremented).
This is another way to do the same thing:
public function scopeFindOrCreate($query, $id)
{
$obj = $query->find($id);
return $obj ?: new static;
}
Instead of creating a static method, you can use a scope in the Model, so the method in the Model will be scopeMethodName and call Model::methodName(), same as you did in the static method, for example
$user = User::findOrCreate(5);
Update:
The firstOrCreate is available in Laravel 5x, the answer is too old and it was given for Laravel-4.0 in 2013.
In Laravel 5.3, the firstOrCreate method has the following declaration:
public function firstOrCreate(array $attributes, array $values = [])
Which means you can use it like this:
User::firstOrCreate(['email' => $email], ['name' => $name]);
User's existence will be only checked via email, but when created, the new record will save both email and name.
API Docs
Alternatively, in this case you can also use Laravel's function and search for id as an attribute, i.e.
$user = User::firstOrCreate(['id' => $id]);
Find or New based on primary key id
$user = User::findOrNew($id); // if exist then update else insert
$user->name= $data['full_name'];
$user->save();
First or New based on non-primary key single filed
// get the record where field_name=value else insert new record
$user = User::firstOrNew(['field_name'=>'value']);
$user->name= $data['full_name'];
$user->save();
First or New based on non-primary key multiple filed
// get the record where field_name1=value1 and field_name2=value2, else insert new record
$user = User::firstOrNew(['field_name1'=>'value1','field_name2'=>'value2']);
$user->name= $data['full_name'];
$user->save();
In Laravel 5:
There are two methods you may use to create models by mass assigning attributes: firstOrCreate and firstOrNew.
The firstOrCreate method will attempt to locate a database record using the given column / value pairs. If the model can not be found in the database, a record will be inserted with the given attributes.
The firstOrNew method, like firstOrCreate will attempt to locate a record in the database matching the given attributes. However, if a model is not found, a new model instance will be returned. Note that the model returned by firstOrNew has not yet been persisted to the database. You will need to call save manually to persist it:
// Retrieve the flight by the attributes, or create it if it doesn't exist...
$flight = App\Flight::firstOrCreate(['name' => 'Flight 10']);
// Retrieve the flight by the attributes, or instantiate a new instance...
$flight = App\Flight::firstOrNew(['name' => 'Flight 10']);
Laravel 4 models have a built-in findOrNew method that does what you need:
$user = User::findOrNew($id);
You can use firstOrCreate (It's working with Laravel 4.2)
$bucketUser = BucketUser::firstOrCreate([
'bucket_id' => '1',
'user_id' => '2',
]);
returns found instance or new instance.

Custom logic for updating a row

I have this table class:
class Songs extends Zend_Db_Table_Abstract
{
protected $_name = 'songs';
protected $_primary = 'song_id';
protected $_rowClass = 'Song';
}
And a class that extends the class above with some custom logic.
class Song extends Zend_Db_Table_Row_Abstract
{
protected function _insert()
{
print_r($this);
// $this does exist
}
protected function _update()
{
print_r($this);
//$this does not existing when updating a row, why not?
}
}
My problem is that when I'm inserting a new row I can use $this in my custom logic.
$row->save(); // $this exists in _insert()
But it doesn't exist when I'm trying to update a row.
$myRow->update($data, $where); // $this does not exists in _update()
Why does $this not exist when I want to do some custom logic before updating a row?
To update a row, you don't use:
$myRow->update($data, $where);
You use:
$myRow->save();
But trying to use update() on a row object should throw an exception.
So I'm guessing you're actually calling the update() function on the table object, and not the row object.
$songs = new Songs();
//...
$songs->update($data, $where);
At that point the row object is never even used, the query is simply generated from the $data array and the $where clause.
If you want to use the custom _update() method you would need to do something like:
$songs = new Songs();
$song = $songs->find($id)
//change some data
$song->save();
Of course is also perfectly valid to add custom logic at the table level, and should be noted while calling an update or insert from the table object does not use the row object, calling save() on the row object proxies the table object.
For example, from the Zend_Db_Table_Row _doInsert() function:
$this->_insert();
//...
$primaryKey = $this->_getTable()->insert($data);
So if you have custom logic that you want to use every time you update a row (whether you update from the table object or the row object), it should be put into the table object.
From the Zend_Db_Table_Row docs:
If you need to do custom logic in a specific table, and the custom logic must occur for every operation on that table, it may make more sense to implement your custom code in the insert(), update() and delete() methods of your Table class. However, sometimes it may be necessary to do custom logic in the Row class.

Categories