Updating a Whole Table (Laravel and Vuejs) - laravel

I have a table on admin panel which contains 60 rows and 10 columns. Those columns belongs 2 different tables in database. Simplified version is like so:
| Asset | Trade | Status | Code | Link |
Code and Link columns contain empty text inputs. When I enter anything, their values go to Vue.js object and I save them in the Posts table which works perfectly fine.
Trade and Status columns have radio buttons and they belong to Trades table. When I check the radio buttons, their values go to Vue.js object. When I try to update the Trades table it returns 405 error.
The button calls that function:
publish() {
this.form.post("/api/posts")
.then(() => {
this.form
.put("/api/trades")
})
.catch(() => {
//error codes...
});
}
I don't know if POST and PUT requests can be used together, or if this is the correct syntax, but I like to make both action with one click.
My update function is down below. As you can see I'm trying to use "asset_id" which is the foreign key in the Trades table, instead of "id" which is primary key of Trades table. I think this causes the problem, but I'm not sure. I also add that line of code to Post modal file, but it didn't help:
protected $primaryKey = 'asset_id';
My update function:
/**
* Update the specified resource in storage.
*
* #param \Illuminate\Http\Request $request
* #param int $asset_id
* #return \Illuminate\Http\Response
*/
public function update(Request $request, $asset_id)
{
$input = $request->all();
if (count($input['asset_id']) > 0) {
foreach ($input['asset_id'] as $asset_id) {
if (array_key_exists($asset_id, $input['status'])) {
$updates = [
'trade' => $input['trade'][$asset_id],
'status' => $input['status'][$asset_id],
'private' => (array_key_exists($asset_id, $input['public_code']) ? 0 : 1)
];
Post::where('asset_id', $asset_id)->find($asset_id)->update($updates);
}
}
}
}
When I check the radio buttons and fill the inputs Vue.js object becomes something like this:
form: new Form([
asset_id: [2, 5, 16, 52],
trade: {
2: "Long",
5: "None",
16: "Long",
52: "Short"
},
status: {
2: "Active",
5: "Canceled",
16: "Pending"
52: "Active"
},
public_code: {
2: "VBFABVR",
16: "hmbtr46"
},
link: {
2: "http://...",
16: : "http://..."
}
])
I'm not sure if I should provide more details. If it's so, please let me know. I hope someone tells me what is wrong here.
EDIT:
Route codes:
Route::apiResources([
'users' => 'API\UsersController',
'roles' => 'API\RolesController',
'plans' => 'API\PlansController',
'categories' => 'API\CategoriesController',
'assets' => 'API\AssetsController',
'posts' => 'API\PostsController',
'trades' => 'API\TradesController',
]);
Route List:
| POST | api/trades | trades.store | App\Http\Controllers\API\TradesController#store | api
| GET|HEAD | api/trades | trades.index | App\Http\Controllers\API\TradesController#index | api
| PUT|PATCH | api/trades/{trade} | trades.update | App\Http\Controllers\API\TradesController#update | api
| GET|HEAD | api/trades/{trade} | trades.show | App\Http\Controllers\API\TradesController#show | api
| DELETE | api/trades/{trade} | trades.destroy | App\Http\Controllers\API\TradesController#destroy | api

It was a rookie mistake. I was trying to pass a collection of the trades to database, but put request requires /api/trades/$id. That's why I've created a for loop in front-end, and in back-end, all I need was a simple update function.
This is the function that is called when I click the submit button:
publish() {
var trades = this.form.asset_id.length;
this.form.post("/api/posts")
for (var i = 0; i < trades; i++) {
if (this.form.asset_id[i] in this.form.status) {
this.form.put("/api/trades/" + this.form.asset_id[i])
}
}
}
And this is the upload function:
public function update(Request $request, $id)
{
$item = Trade::findOrFail($id);
$input = $request->all();
$updates = [
'trade' => $input['trade'][$id],
'status' => $input['status'][$id],
'private' => (array_key_exists($id, $input['public_code']) ? 0 : 1)
];
$item->update($updates);
}

Related

Laravel model observer method doesn't get fired

In my Laravel (7.x) I am trying to use Observers for updating device_inventories table if the value of the record if the record of the subscriber_devices table is updated as inactive.
device_inventories | subscriber_devices
----------------------- | --------------------------------
# | title | status | # | device_inventory_id | status
----------------------- | --------------------------------
1 | device-1 | active | 1 | 1 | active
2 | device-2 | active | 2 | 2 | active
For example:
Suppose I update the record id = 2 of subscriber_devices to status = inactive then the value of device_inventories / status should be updated to replacement. Assuming, that the device was damaged and needs to be sent for replacement.
AppServiceProvider.php
use App\SubscriberDevice;
use App\Observers\ObserverChangeDeviceInventoryStatusToReplacement;
class AppServiceProvider extends ServiceProvider
{
public function boot()
{
SubscriberDevice::observe(ObserverChangeDeviceInventoryStatusToReplacement::class);
}
}
App\Observers\ObserverChangeDeviceInventoryStatusToReplacement.php
use App\DeviceInventory;
use App\SubscriberDevice;
class ObserverChangeDeviceInventoryStatusToReplacement
{
public function updated(SubscriberDevice $SubscriberDevice)
{
DeviceInventory::where('id', $SubscriberDevice->device_inventory_id)->update([
'status' => 'replacement'
]);
}
}
App\SubscriberDevice.php
class SubscriberDevice extends Model
{
protected $table = 'subscriber_devices';
public function _status($token, $reason)
{
self::where('token', $token)->update([
'reason' => $reason,
'status' => 'inactive',
]);
}
}
The observer method doesn't seems to be firing. What am I doing wrong.?
Thanks to #EmptyBrain.
App\SubscriberDevice.php
class SubscriberDevice extends Model
{
protected $table = 'subscriber_devices';
public function _status($token, $reason)
{
$self = self::where('token', $token)->first();
$self->update([
'reason' => $reason,
'status' => 'inactive',
]);
}
}
Reference laravel Eloquent model update event is not fired

validation rule unique in laravel

I want to do a validation of two fields, I have tried but it does not work for me, exactly what I need is for two fields to be validated.
what I want is that the namames of fields "grado" and "fk_nivel_academico" are not repeated
This is the table in my database:
-----------------------------------------------
id | grado | fk_nivel_academico | fk_estado
1 | Primero | 1 | 1
2 | Segundo | 1 | 2
This is the validation rule:
$validatedData = Validator::make(
[
'grado' => $this->grado
],
[
'grado' => [
'required',
Rule::unique('grado')
->where('fk_nivel_academico', '==', $this->fk_nivel_academico)
->where('grado', '==', $this->grado)
]
],
I think the problem it's that you are using the == comparator when in sql it is =.
The other solution I would recommend you to use, is to make a Rule file.
Here's a guide How to create custom validation
And in the passes method you could use something like this
public function passes($attribute, $value)
{
$table = Table::where('fk_nivel_academico', '=', $this->fk_nivel_academico)
->where('grado', '=', $this->grado)->get();
if($table->count() == 0){
return true;
}
}

How to validate 2 Laravel fields in a NAND way

I'm looking for a solution to the following case: my controller action receives 2 variables, however they must exclude eachother. So you can pass either 1 of them or none.
The following truth table arises (NAND):
| A | B | Result |
|---|---|--------|
| 0 | 0 | 1 |
| 0 | 1 | 1 |
| 1 | 0 | 1 |
| 1 | 1 | 0 |
(say A equals points and B equals coupon).
// MyController.php
$this->validate($request, [
'points' => '',
'coupon' => ''
]);
I've tried some solutions like nullable|required_without:field_name but those seem to result in an XOR, which means you must pass at least 1 of them.
I've decided to create a new rule called without:field1,field2:
Validator::extend('without', function($attribute, $value, $parameters, \Illuminate\Validation\Validator $validator) {
foreach($parameters as $compare) {
// Check if the given parameters are filled in, if so we return `false`.
if($validator->validateRequired(null, array_get($validator->getData(), $compare))) {
return false;
}
}
// No `without` parameters have been found, validation successful.
return true;
});
// Replace the error message placeholders.
Validator::replacer('without', function ($message, $attribute, $rule, $parameters, \Illuminate\Validation\Validator $validator) {
$attributes = [];
foreach ($parameters as $key => $value) {
$attributes[$key] = $validator->getDisplayableAttribute($value);
}
return str_replace(':values', implode(' / ', $attributes), $message);
});
Next, add a translation to resources/lang/en/validation.php:
'without' => 'The :attribute may not be set with :values',
Then you can simply use it like this:
$this->validate($request, [
'points' => 'nullable|without:coupon',
'coupon' => 'nullable|without:points'
]);
(you may add multiple parameters like without:coupon,user_id)
Which makes sure that:
Passing pointsand coupon together results in a validation error
Passing a single one of them is OK
Passing neither of them is OK

Save Eloquent model with relation make two entries, why?

This is my controller method:
public function store(Request $request, $course_id){
$price['value'] = $request->price;
$price['desc'] = $request->desc;
If ($request->promo === "on") {
$price['promo'] = 1;
} else {
$price['promo'] = 0;
}
$course = Course::find($course_id);
Price::create($price)->courses()->save($course);
return redirect('/course/'.$course_id.'/edit');
}
For example if my request var have:
$request->price = 100
$request->desc = 'blablabla'
$request->promo = 'on'
After I submit the form I got two new rows with the same data:
Table prices:
id | price | desc | promo
1 | 100 | blablabla | on
2 | 100 | blablabla | on
Some info on models, I've:
public function courses () {
return $this->belongsToMany('App\Course', 'course_price');
}
in prices model and:
public function prices () {
return $this->belongsToMany('App\Price', 'course_price');
}
in courses model.
Whats wrong?
Try attach:
$price = Price::create($price);
$price->courses()->attach($course_id);
instead of:
$course = Course::find($course_id);
Price::create($price)->courses()->save($course);
it's looks like you make double post request on
Price::create($price)->courses()->save($course);
create and save.
please try your code with
Price::create($price)->courses();

Share value from database in all view in laravel 5

I'm new to laravel. I'm trying to create a simple app with some variable that shouold be in every view. So I create a setting model, with many fields and a unique slug field. Now to share this variable from database I've created a middleware:
public function handle($request, Closure $next)
{
$site_settings = Cache::remember('settings', 60, function() {
return Setting::all();
});
view()->share('site_settings', $site_settings);
return $next($request);
}
Now to show this variable in view I have:
{{{ $site_settings->get(0)->value }}}
This works great, but I'd like to have a more intuitive code in my view, accessing the setting by slug. Something like:
{{{ $site_settings->findBySlug("MYVARIABLE")->value }}}
So it's possible to filter collection by an unique slug?
Info:
This assumes your settings table structure is as following:
----------------------
| id | key | value |
----------------------
| 1 | titleĀ | foo |
| 2 | asd | bar |
| 3 | qqq | zzz |
----------------------
Steps
Step 1: Put the following newCollection method into App\Setting model:
class Settings extends ... {
public function newCollection(array $models = array())
{
return new \App\Collections\SettingsCollection($models);
}
}
Step 2: Put the following lines into App\Collections\SettingsCollection class:
<?php namespace App\Collections;
use Illuminate\Database\Eloquent\Collection;
class SettingsCollection extends Collection {
public function get($name, $default = null)
{
return array_first($this->items, function($itemKey, $model) use ($name)
{
return $model->key == $name;
}, $default)->value;
}
}
Step 3: Enjoy! This is the collection I'm currently using. Instead of this:
$settings = Setting::all();
$settings->where('key', 'key_name')->first()->value;
You can simply just do this:
$settings = Setting::all();
echo $settings->get('key_name'); // returns value of the setting with the key 'title'
Maybe a query scope would fit.
In your model:
public function scopeFindBySlug($slug){
return $query->where('slug','=', $slug);
}
So you will have: $site_settings->findBySlug('your_slug')->get();

Resources