Standard RESTful controller or model ignores PUT verb in Yii 2 - model-view-controller

tl;dr I have followed the official guide. Everything seems working except for PUT/PATCH verb. The 200 OK code is returned, but the actual model isn't updated. What can be wrong?
I have created a blank Yii 2 project that have created a REST UserController for already existing User model:
namespace app\controllers;
use yii\rest\ActiveController;
class UserController extends ActiveController
{
public $modelClass = 'app\models\User';
}
I have modified the model to have all fields safe:
public function rules()
{
return [
['status', 'default', 'value' => self::STATUS_INACTIVE],
['status', 'in', 'range' => [self::STATUS_ACTIVE, self::STATUS_INACTIVE, self::STATUS_DELETED]],
[['username', 'email'], 'required'],
[['username', 'email'], 'unique'],
['email', 'email'],
[['password_hash', 'password_reset_token', 'verification_token', 'auth_key', 'status,created_at', 'updated_at', 'password'], 'safe'],
];
}
I have configured URL rules to have both pluralized and non-pluralized paths:
'urlManager' => [
'enablePrettyUrl' => true,
'enableStrictParsing' => true,
'showScriptName' => false,
'rules' => [
[
'class' => 'yii\rest\UrlRule',
'controller' => 'user',
'pluralize' => false,
'except' => ['index'],
],
[
'class' => 'yii\rest\UrlRule',
'controller' => 'user',
'patterns' => [
'GET,HEAD,OPTIONS' => 'index',
],
],
],
I have enabled JSON input, if that matters:
'request' => [
'parsers' => [
'application/json' => 'yii\web\JsonParser',
]
]
All the verbs are processed correctly except for PATCH /users/123 / PUT /users/123. When executed in Insomnia, I am getting 200 OK, but the returned record shows no sign of modification:
What can be wrong or what am I missing?

Related

Codeigniter 4 - Store validation rules in separate files

I have all my rules in the Validation config file, like the documentation suggest:
https://codeigniter4.github.io/userguide/libraries/validation.html#saving-sets-of-validation-rules-to-the-config-file
For example:
public $userCreate = [
'first_name' => [
'label' => 'First Name',
'rules' => 'required|string|max_length[60]'
],
'last_name' => [
'label' => 'Last Name',
'rules' => 'required|string|max_length[60]',
],
'email' => [
'label' => 'Auth.email',
'rules' => 'required|max_length[254]|valid_email|is_unique[users.email]',
],
];
In my controllers I can access my validation groups like this:
$validation = \Config\Services::validation();
$rules = $validation->getRuleGroup('userCreate');
As my app gets bigger, I need more and more validation rules, so the question is, is there a way to organize them in separate files and not to have all of them in a single config file? Something like the custom rules, which are loaded in the config file and stored separately.
Steps
Create a custom directory for storing your validation rules. I.e app/Validation.
Create a class under that directory for your 'User' rules. I.e: app/Validation/UserRules.php
<?php
namespace App\Validation;
class UserRules
{
public function create()
{
return [
'first_name' => [
'label' => 'First Name',
'rules' => 'required|string|max_length[60]'
],
'last_name' => [
'label' => 'Last Name',
'rules' => 'required|string|max_length[60]',
],
'email' => [
'label' => 'Auth.email',
'rules' => 'required|max_length[254]|valid_email|is_unique[users.email]',
],
];
}
public function update()
{
return [
// Add 'User' update rules here.
];
}
}
In the \Config\Validation config file, set the relevant 'User' validation rules in the constructor. I.e:
<?php
namespace Config;
use CodeIgniter\Config\BaseConfig;
// ...
class Validation extends BaseConfig
{
// --------------------------------------------------------------------
// Setup
// --------------------------------------------------------------------
public $userCreate = [];
public $userUpdate = [];
public function __construct()
{
$this->userCreate = ($userRules = new \App\Validation\UserRules())->create();
$this->userUpdate = $userRules->update();
}
// ...
}
In your Controllers, you may access validation groups as usual.
Thanks to #steven7mwesigwa I came up with a solution that suits me the most.
First I created separate classes inside the App/Validation folder. For example these 2 classes:
App\Validation\Auth.php
<?php
namespace App\Validation;
class Auth {
public $login = [
'email' => [
'label' => 'E-mail',
'rules' => 'required|max_length[254]|valid_email',
],
'password' => [
'label' => 'Password',
'rules' => 'required',
],
'remember' => [
'label' => 'Remember me',
'rules' => 'if_exist|permit_empty|integer',
]
];
}
App\Validation\User.php
<?php
namespace App\Validation;
class User {
public $userCreate = [
'first_name' => [
'label' => 'First Name',
'rules' => 'required|string|max_length[60]',
],
'last_name' => [
'label' => 'Last Name',
'rules' => 'required|string|max_length[60]',
],
'email' => [
'label' => 'E-mail',
'rules' => 'required|max_length[254]|valid_email|is_unique[users.email]',
],
];
}
The next step is to add a construct method to the existing validation config file:
App\Config\Validation.php
<?php
namespace Config;
use CodeIgniter\Config\BaseConfig;
class Validation extends BaseConfig {
...
// --------------------------------------------------------------------
// Rules
// --------------------------------------------------------------------
public function __construct() {
$ruleGroups = [
new \App\Validation\Auth(),
new \App\Validation\User(),
];
foreach ($ruleGroups as $ruleGroupClass) {
foreach ((array) $ruleGroupClass as $groupName => $rules) {
$this->{$groupName} = $rules;
}
}
}
}

Laravel-Auditing is not working without any errors

I've recently installed this package and configured everything with guide but some how it's not working!
By it's not working I mean it's not adding anything to database. I really don't know what is wrong with my configs but I've checked everything with guide 3 times and everything is correct but... I don't know
config/audit.php:
<?php
return [
'enabled' => env('AUDITING_ENABLED', true),
'implementation' => OwenIt\Auditing\Models\Audit::class,
'user' => [
'morph_prefix' => 'user',
'guards' => [
'web',
'api',
],
],
'resolver' => [
'user' => OwenIt\Auditing\Resolvers\UserResolver::class,
'ip_address' => OwenIt\Auditing\Resolvers\IpAddressResolver::class,
'user_agent' => OwenIt\Auditing\Resolvers\UserAgentResolver::class,
'url' => OwenIt\Auditing\Resolvers\UrlResolver::class,
],
'events' => [
'created',
'updated',
'deleted',
'restored',
'gold_mailed' => 'goldMailed',
'invited' => 'clientInvited',
],
'strict' => false,
'timestamps' => false,
'threshold' => 0,
'driver' => 'session',
'drivers' => [
'eloquent' => [
'table' => 'audits',
'connection' => null,
],
],
'console' => true,
];
My model that I want to audit:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use OwenIt\Auditing\Contracts\Auditable;
use App\Models\Expansion;
use App\Models\Audit;
class Setting extends Model implements Auditable
{
protected $table = 'settings';
use \OwenIt\Auditing\Auditable;
protected $fillable = [
'expansion_id', 'season', 'advertiser_app', 'pvp_app', 'raid_app', 'version'
];
protected $auditInclude = [
'expansion_id', 'season', 'advertiser_app', 'pvp_app', 'raid_app', 'version'
];
public function Expansion()
{
return $this->hasOne(Expansion::class, 'id', 'expansion_id');
}
}
web.php:
Route::post('/setting' , 'Admin\SuperAdminController#saveSetting')->middleware('superadmin')->name('admin_save_setting');
Controller:
public function saveSetting(Request $request)
{
$sql = Setting::where('id', 1)->update([
'expansion_id' => $request['expansion_id'],
'season' => $request['season'],
'advertiser_app' => $request['advertiser_app'],
'pvp_app' => $request['pvp_app'],
'raid_app' => $request['raid_app'],
'version' => $request['version']
]);
if ($sql) {
toastr()->success('Settings successfully updated.');
return redirect()->back();
}
toastr()->error('Something went wrong!');
return redirect()->back();
}
I don't know what infos do you need but I think this is enough
I think my problem is with "driver" in config file , I don't know if that's correct or not
[UPDATED]
Based on the controller code you showed, it didn't work because your code is being called using Builder style, and the package only works when it is called using Eloquent style.
Documentation link
So, maybe you need to change your code to:
$setting = Setting::where('id', 1)->firstOrFail();
$setting->update([
'expansion_id' => $request['expansion_id'],
'season' => $request['season'],
'advertiser_app' => $request['advertiser_app'],
'pvp_app' => $request['pvp_app'],
'raid_app' => $request['raid_app'],
'version' => $request['version']
]);
now I have another problem -_-
this is my controller:
$sql = Raid::findOrFail($request['id']);
$sql = $sql->update($request->all());
I have a array in my table , after update value will be like this:
"{\"Plate\":0,\"Cloth\":0,\"Mail\":0,\"Leather\":0}"
but it should be:
{"Plate":"0","Cloth":"0","Mail":"0","Leather":"0"}
so I will get an error
before this , I was updating like this and it was ok:
$sql = Raid::where('id', $request['id'])->update($request->all());
and this is my mode (traders and class_traders is fields that I have problem with):
use SoftDeletes;
use \OwenIt\Auditing\Auditable;
protected $table = 'raid';
protected $dates = ['date_and_time','deleted_at'];
protected $fillable = [
'admin_id', '....
];
protected $casts = [
'bosses' => 'array',
'traders' => 'array',
'class_traders' => 'array',
'boosters' => 'array',
];

How can I create a Laravel Resource relationship for a belongsTo?

I have created a UserResource that is successfully returning all of my user attributes, including the organization it belongs to. It looks something like this:
Resources/User.php
return [
'type' => 'users',
'id' => (string)$this->id,
'attributes' => [
'name' => $this->name,
'email' => $this->email,
...
'relationships' => [
'organization' => $this->organization,
],
];
In my User model, there is a belongsTo relationship for User->Organization.
Instead of returning the actual organization model, I'd like to return the organization resource.
For example, an organization hasMany locations:
Resources/Organization.php
return [
'type' => 'organizations',
'id' => (string)$this->id,
'attributes' => [
'name' => $this->name,
...
'relationships' => [
'locations' => Location::collection($this->locations),
],
];
I can successfully return the collection of locations that belong to the organization. I have not been able to return a belongsTo relationship.
I've tried:
Resources/User.php
'relationships' => [
'organization' => Organization::collection($this->organization),
],
// or this
'relationships' => [
'organization' => Organization::class($this->organization),
],
// or this
use App\Http\Resources\Organization as OrganizationResource;
...
'relationships' => [
'organization' => OrganizationResource($this->organization),
],
How can I return a single model as a related resource? Thank you for any suggestions!
Have you tried it with the new keyword?
'relationships' => [
'organization' => new OrganizationResource($this->organization),
],

CakePHP IntegrationTestTrait Post Returns HTTP Status 302

I am trying to perform a simple test from posting data onto a table in CakePHP. I am using IntegrationTestTrait.
I am not able to POST data successfully. My $this->_response is yielding:
object(Cake\Http\Response) {
'status' => (int) 302,
'contentType' => 'text/html',
'headers' => [
'Content-Type' => [
(int) 0 => 'text/html; charset=UTF-8'
],
'Location' => [
(int) 0 => '/'
]
],
'file' => null,
'fileRange' => [],
'cookies' => object(Cake\Http\Cookie\CookieCollection) {
[protected] cookies => []
},
'cacheDirectives' => [],
'body' => ''
}
My TestCase code looks like this:
public function testAddStudentSuccess() {
$data = [
'last_name' => 'Test',
'first_name' => '05',
'middle_name' => '',
'preferred_name' => '',
'id_number' => '10005',
'contact_id' => '',
'users[0][email]' => 'test_05#email.com'
];
//Test Pre-condition
$query = $this->Students->find('all')->where([
'id_number' => $data['id_number']
]);
$this->post('/students/add', $data);
debug($this->_response);
}
I debugged further and found that the Test is not even invoking the Controller add() functions.
I thought the issue was an Authentication Issue is I tried following all the authentication work arounds prescribed in the documentation. However, it did not work.
Does anyone know how I can debug this further? Any help is appreciated. Thank you.

How to add fields which are not available in database?

I am not able to add field which is not available in my database
I have tried adding
$this->crud->addFields([
[
'name' => 'coupon_type',
'label' => 'Coupon For',
'type' => 'select_from_array',
'options' => [
// Options
],
'allows_null' => true,
'default' => 1,
'attributes' => [
'id' => 'coupon_type'
]
]
]);
I want to add fields in my create page.
You can do this by defining accessors for your "virtual" attributes
public function getIsAdminAttribute()
{
return $this->attributes['admin'] == 'yes';
}
and defining the appends on your model
protected $appends = ['is_admin'];
Find everything in the docs here:
https://laravel.com/docs/5.8/eloquent-serialization#appending-values-to-json

Resources