i have an update method like below which is so big and i want to manage it some how that in take less place in controller and make controller much cleaner now i want to know if there is any way to make it as service or some thing this is my update method for example :
public function update(Request $request, Something $something)
{
$something->somefield = $request->get('field1');
$something->somefield = $request->get('field1');
$something->somefield = $request->get('field1');
$something->somefield = $request->get('field1');
$something->save();
return response()->json($something, 200);
//consider i may have like 20 fields here
Use update() method to update all fields
public function update(Request $request, Something $something)
{
$something->update($request->all());
return response()->json($something, 200);
}
For me the appropriate way to do this is to name the input fields of the form and fields of the table same. Then you can just use $something->update($request->all());
Use below code in case fields not present in db passed.
$something->update($request->only($field1, $field2));
Related
Edit function:
public function editCheck($id, LanguagesRequest $request)
{
try{
$language = language::select()->find($id);
$language::update($request->except('_token'));
return redirect()->route('admin.languages')->with(['sucess' => 'edit done by sucsses']);
} catch(Exception $ex) {
return redirect()->route('admin.addlanguages');
}
}
and model or select function
public function scopeselect()
{
return DB::table('languages')->select('id', 'name', 'abbr', 'direction', 'locale', 'active')->get();
}
This code is very inefficient, you're selecting every record in the table, then filtering it to find your ID. This will be slow, and is entirely unnecessary. Neither are you using any of the Laravel features specifically designed to make this kind of thing easy.
Assuming you have a model named Language, if you use route model binding, thing are much simpler:
Make sure your route uses the word language as the placeholder, eg maybe your route for this method looks like:
Route::post('/languages/check/{language}', 'LanguagesController#editCheck');
Type hint the language as a parameter in the method:
public function editCheck(Language $language, LanguagesRequest $request) {
Done - $language is now the single model you were afer, you can use it without any selecting, filtering, finding - Laravel has done it all for you.
public function editCheck(Language $language, LanguagesRequest $request) {
// $language is now your model, ready to work with
$language::update($request->except('_token'));
// ... etc
If you can't use route model binding, or don't want to, you can still make this much simpler and more efficient. Again assuming you have a Language model:
public function editCheck($id, LanguagesRequest $request) {
$language = Language::find($id);
$language::update($request->except('_token'));
// ... etc
Delete the scopeselect() method, you should never be selecting every record in your table. Additionally the word select is surely a reserved word, trying to use a function named that is bound to cause problems.
scopeselect() is returning a Collection, which you're then trying to filter with ->find() which is a method on QueryBuilders.
You can instead filter with ->filter() or ->first() as suggested in this answer
$language = language::select()->first(function($item) use ($id) {
return $item->id == $id;
});
That being said, you should really find a different way to do all of this entirely. You should be using $id with Eloquent to get the object you're after in the first instance.
I have a form that is sending the values to the controller in this way:
public function postFormUpdate(ProjectUpdateRequest $request)
{
$inputs = $request->all();
$project = $this->projectRepository->update($inputs['project_id'],$inputs);
//...
}
The project repository is done this way:
public function update($id, Array $inputs)
{
return $this->save($this->getById($id), $inputs);
}
private function save(Project $project, Array $inputs)
{
// Nullable
if (isset($inputs['project_type'])) {$project->project_type = $inputs['project_type'];}
if (isset($inputs['activity_type'])) {$project->activity_type = $inputs['activity_type'];}
...
}
My problem is if the project_type is null from the form field (the project type doesn't need to be entered or can be removed), then isset($inputs['project_type']) will be false and the update will not be triggered.
What I want is if the user had set up a project type and then wants to change it and set it to null, like this, it is not working. I use the isset because sometimes I update only one field and I don't want this to generate an error because it was not part of the inputs and was not set.
What I can do is use:
if (isset($inputs['project_type']) || is_null($inputs['project_type'])) {$project->project_type = $inputs['project_type'];}
But I am looking if there is a more elegant way to do this.
Thanks.
A more elegant way would be to see if anything is set under the key.
so go with array_key_exists
if ( array_key_exists('project_type', $inputs) ){$project->project_type = $inputs['project_type'];}
You may see it in action here
I need a little help and I can’t find an answer. I would like to replicate a row from one data table to another. My code is:
public function getClone($id) {
$item = Post::find($id);
$clone = $item->replicate();
unset($clone['name'],$clone['price']);
$data = json_decode($clone, true);
Order::create($data);
$orders = Order::orderBy('price', 'asc')->paginate(5);
return redirect ('/orders')->with('success', 'Success');
}
and i got an error :
"Missing argument 1 for
App\Http\Controllers\OrdersController::getClone()"
.
I have two models: Post and Order. After trying to walk around and write something like this:
public function getClone(Post $id) {
...
}
I got another error
Method replicate does not exist.
Where‘s my mistake? What wrong have i done? Maybe i should use another function? Do i need any additional file or code snippet used for json_decode ?
First of all, make sure your controller gets the $id parameter - you can read more about how routing works in Laravel here: https://laravel.com/docs/5.4/routing
Route::get('getClone/{id}','YourController#getClone');
Then, call the URL that contains the ID, e.g.:
localhost:8000/getClone/5
If you want to create an Order object based on a Post object, the following code will do the trick:
public function getClone($id) {
// find post with given ID
$post = Post::findOrFail($id);
// get all Post attributes
$data = $post->attributesToArray();
// remove name and price attributes
$data = array_except($data, ['name', 'price']);
// create new Order based on Post's data
$order = Order::create($data);
return redirect ('/orders')->with('success', 'Success');
}
By writing
public function getClone(Post $id)
you are telling the script that this function needs a variable $id from class Post, so you can rewrite this code like this :
public function getClone(){
$id = new Post;
}
However, in your case this does not make any sence, because you need and integer, from which you can find the required model.
To make things correct, you should look at your routes, because the url that executes this function is not correct, for example, if you have defined a route like this :
Route::get('getClone/{id}','YourController#getClone');
then the Url you are looking for is something like this :
localhost:8000/getClone/5
So that "5" is the actual ID of the post, and if its correct, then Post::find($id) will return the post and you will be able to replicate it, if not, it will return null and you will not be able to do so.
$item = Post::find($id);
if(!$item){
abort(404)
}
Using this will make a 404 page not found error, meaning that the ID is incorrect.
Is there any way to update a record in Laravel using eloquent models just if a change has been made to that record? I don't want any user requesting the database for no good reason over and over, just hitting the button to save changes. I have a javascript function that enables and disables the save button according with whether something has changed in the page, but I would like to know if it's possible to make sure to do this kind of feature on the server side too. I know I can accomplish it by myself (meaning: without appealing to an internal functionality of the framework) just by checking if the record has change, but before doing it that way, I would like to know if Laravel eloquent model already takes care of that, so I don't need to re-invent the wheel.
This is the way I use to update a record:
$product = Product::find($data["id"]);
$product->title = $data["title"];
$product->description = $data["description"];
$product->price = $data["price"];
//etc (string values were previously sanitized for xss attacks)
$product->save();
You're already doing it!
save() will check if something in the model has changed. If it hasn't it won't run a db query.
Here's the relevant part of code in Illuminate\Database\Eloquent\Model#performUpdate:
protected function performUpdate(Builder $query, array $options = [])
{
$dirty = $this->getDirty();
if (count($dirty) > 0)
{
// runs update query
}
return true;
}
The getDirty() method simply compares the current attributes with a copy saved in original when the model is created. This is done in the syncOriginal() method:
public function __construct(array $attributes = array())
{
$this->bootIfNotBooted();
$this->syncOriginal();
$this->fill($attributes);
}
public function syncOriginal()
{
$this->original = $this->attributes;
return $this;
}
If you want to check if the model is dirty just call isDirty():
if($product->isDirty()){
// changes have been made
}
Or if you want to check a certain attribute:
if($product->isDirty('price')){
// price has changed
}
You can use $product->getChanges() on Eloquent model even after persisting. Check docs here
I like to add this method, if you are using an edit form, you can use this code to save the changes in your update(Request $request, $id) function:
$post = Post::find($id);
$post->fill($request->input())->save();
keep in mind that you have to name your inputs with the same column name. The fill() function will do all the work for you :)
use only this:
Product::where('id', $id)->update($request->except(['_token', '_method']));
At times you need to compare the newly changed value with the previous one and if you are looking for that here is the solution.
if (
$obj->isDirty('some_field_name') &&
$obj->some_field_name != $obj->getOriginal('some_field_name')
) {
// Make required changes...
}
});
}
The reference of the derived solution is here.
Maybe Laravel has updated since, but wasChanged is working for me better than isDirty in all of these previous answers.
For example:
if($post->wasChanged('status') && $post->status == 'Ready') // Do thing
Basically, I'm writing a simple blogging application where users can vote up or down on posts (I've named this process scoring inside my application). My problem is I am not sure what the best approach is for accessing a method to determine if the user has voted or not on the post, as I don't want to pass a repository into my view nor do I want the model to have methods mimicking the repository... Here are those two ideas - are these the only approaches?
The first approach requires that I pass a PostRepository to my views as well as the Post model which is already passed...
<!-- Repository-in-view approach -->
<p>You voted {{ $postRepository->hasUserScored($post->id, $user->id) ? 'up' : 'down' }}.</p>
-----------
// Inside `PostRepository`
public function hasUserScored($postId, $userId, $vote = true)
{
// DB logic to determine ...
}
Or should I maybe do something like this?
<!-- Repository-in-view approach -->
<p>You voted {{ $post->hasUserScored($user->id) ? 'up' : 'down' }}.</p>
-----------
// Inside `Post`
public function hasUserScored($userId)
{
return (new PostRepository)->hasUserScored($this->id, $userId);
}
// Inside `PostRepository`
public function hasUserScored($postId, $userId, $vote = true)
{
// DB logic to determine ...
}
What is the best way to overcome this? Any help greatly appreciated, thanks!
Best practice is to avoid calling functions from within views.
Either call the function from the controller, and pass that data to the view. Or, alternatively, use a view composer.
Why do you do this in such a complicated way? Can't your Post model just have many-to-many relationship with users + pivot table? Then, checking a User vote is as simple as:
function users()
{
return $this->belongsToMany('User')->withPivot('vote');
}
function getUserScore($userId)
{
return $this->users->find($userId)->pivot->vote;
}
Also, if you want to check whether a user has voted or not, simply do:
function hasUserVoted($userId)
{
return $this->users->contains($userId);
}
you have to pass the Repository to the view.. although what you want to do is not the smartest approach but according with what you need.. the way is
on your controller __construct you add something like this
function __construct(PostRepositoryInterface $post){
$this->post = $post;
}
if you dont use interface then just pass the repository
then you return to the view
view(your.view)->with('post', $this->post);
then you are done..