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
Related
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));
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.
Looking for better execution of the below function, specifically dealing with checkboxes.
/**
* Update the specified resource in storage.
*
* #param int $id
* #return Response
*/
public function update(CreateUserRequest $request, $id)
{
$user = User::find($id);
//TODO should be else where?
$input = $request->all();
if(isset($input['status'])) $input['status'] = 1;
else $input['status'] = 0;
$user->fill($input)->save();
return redirect('admin/users');
}
I think you are doing fine, but you can test the value of status as the string 'yes'. Unchecked checkboxes just don't register anything, so you're going to be doing essentially the same thing. Assuming your checkbox input has value="yes", then:
$input = $request->all();
if($input['status'] === 'yes') $input['status'] = 1;
else $input['status'] = 0;
Pretty much no matter what, you're going to have to have the 'else' to define some value for the unchecked case. It's really just a matter of what you want to use for the checked value. You could even make it 1, but the unchecked case wouldn't be 0, you'd still need this condition to assign it.
If you're wanting to get the logic out of your controller, you might have tried setting the field default the field to 0 in your DDL, then in your model implementing the mutator (setter):
class User extends Eloquent {
public function setStatusAttribute($value)
{
$this->attributes['status'] = 1;
}
}
The trouble here is that this won't get called if you don't have status in your input and you won't have it if the checkbox is unchecked. Thus it won't unset it if the user sets and unsets.
Hence, to the best of my knowledge, we all generate both true and false values for the input in the controller as a conventional practice. You're only real choice is what value you prefer to set on the input in the form.
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
I am trying to write a validator in Zend framework.
The validator queries the database to check if a particular record exists, this query uses a where clause. The value for the where clause is specified by another field on the form, so how do I pass this value into the validator?
This is how I add my validator:
$adgroup_name->addValidator(new Generic_ValidateUniqueAdGroupName() ); break;
Within my validator I have:
// Query which gets an array of existing ad group names in db
$q = Doctrine_Query::create()
->select('a.name')
->from('AdGroup a')
->where('a.name = ?', $value)
->andWhere('a.campaign_id = ?', $campaign_id);
$adgroup_names_result = $q->fetchOne(array(), Doctrine::HYDRATE_ARRAY);
How do I pass in $campaign_id? I've tried the following and it doesn't work:
$adgroup_name->addValidator(new Generic_ValidateUniqueAdGroupName($campaign_id) ); break;
The principle is the same as used in "confirm password" validators. You need the value of another element in the form in the field when the form is submitted. That's why attempting to instantiate the validator with the campaign_id is not working: the value of $campaign_id is not yet set.
When an element calls isValid() on its validators, it passes a second parameter called $context that is filled with an array of submitted form values. So your isValid() method in your validator should look something like this:
public function isValid($value, $context = null)
{
$campaign_id = $context['campaign_id'];
// Now build your query using $value - from the element to which this
// validator is attached - and the $campaign_id provided by the context.
// And, of course, return true/false as required.
}
I think to make new Generic_ValidateUniqueAdGroupName($campaign_id) work you need to define a constructor for Generic_ValidateUniqueAdGroupName class and a variable called e.g. $_campaign_id. A draft is below:
class Generic_ValidateUniqueAdGroupName extends Zend_Validate_Abstract {
protected $_campaign_id;
public function __construct($campaign_id) {
$this->_campaign_id = $campaign_id;
}
}
With this, you would access the id in your query as $this->_campaign_id.
You need to supply the $options argument:
Implementation in Zend_Form_Element:
public function addValidator($validator, $breakChainOnFailure = false, $options = array())
So, you'd do something like this:
$validator = new new Generic_ValidateUniqueAdGroupName();
$adgroup_name
->addValidator($validator, false, array('campaign_id' => 1));