REST api not working - php

I am new to php development. Just for practicing I am creating a rest API following a video tutorial. I have followed each and every step but still unable to get the desired result. Below is the code
Employee Model
class Employee extends \yii\db\ActiveRecord
{
const SCENARIO_CREATE = 'create';
/**
* #inheritdoc
*/
public static function tableName()
{
return 'employee';
}
/**
* #inheritdoc
*/
public function rules()
{
return [
[['emp_name', 'emp_email', 'emp_sal'], 'required'],
[['emp_name', 'emp_email', 'emp_sal'], 'string', 'max' => 100],
];
}
public function scenarios()
{
$scenarios = parent::scenarios();
$scenarios['create'] = ['emp_name','emp_email', 'emp_sal'];
return $scenarios;
}
/**
* #inheritdoc
*/
public function attributeLabels()
{
return [
'id' => 'ID',
'emp_name' => 'Emp Name',
'emp_email' => 'Emp Email',
'emp_sal' => 'Emp Sal',
];
}
}
Above the ID field is auto-increment
Employee Controller
public function actionCreateEmployee()
{
\Yii::$app->response->format= \yii\web\Response::FORMAT_JSON;
$employee = new Employee();
$employee-> scenario = Employee::SCENARIO_CREATE;
$employee->attributes = \Yii::$app->request->post();
if ($employee->validate())
{
return array('status'=> true, 'data' => 'Employee Created Sussessfully');
}
else
{
return array('status'=> false, 'data'=>$employee->getErrors());
}
//return array('status'=> true);
}
Now when I run the API in Postman. I got the following result.
Though I have entered all the required fields data still it gives me false status
Any help would be highly appreciated

You need to select x-www-form-urlencoded
The documentation says that the $_POST-parameter only gets filled on application/x-www-form-urlencoded or multipart/form-data and yii is probably using this.
An associative array of variables passed to the current script via the HTTP POST method when using application/x-www-form-urlencoded or multipart/form-data as the HTTP Content-Type in the request.
from php.net

Related

Laravel model observer updated & deleted events are not trigerring?

Observer
class FileLogObserver
{
public function updated(FileLogs $fileLogs)
{
$fileChangeLogs = FileChangeLogs::firstWhere('fileId', $fileLogs->filedId);
if ( !empty($fileChangeLogs)) {
$fileChangeLogs->save([
'logDetails' => '1 file updated',
]);
}
}
}
Controller
class FileLogController extends Controller
{
public function update(Request $request,$id){
$validator = Validator::make(
$request->all(),
[
'orderId' => 'required|integer',
'fileId' => 'required|integer',
'status' => 'required|string'
]
);
if ($validator->fails()) {
return response()->json($validator->errors(), 400);
}
$data = FileLogs::find($id);
if($data){
$data->orderId=$request->orderId;
$data->fileId=$request->fileId;
$data->status=$request->status;
$data->update();
return response()->json(['status'=>'success','StatusCode'=> 200,'message'=>'Successfully Updated','data'=>$data]);
}
else{
return response()->json(['status'=>'Failed','message'=>'Update Failed'],400);
}
}
}
The created & retrieved methods are being properly triggered. However, the updated & deleted methods not triggered. Gone through many links & read that a reason can be becoz the update is not directly on the model. so, i tried like below in my controller. But update function is not working this method. I'm using Laravel-8 version. Any help is much appreciated.
$data = FileLogs::find($id);
if($data){
$data->update(['$data->orderId'=>'$request->orderId','$data->fileId'=>'$request->fileId','$data->status'=>'$request->status']);
you need to register those observer in App\Providers\EventServiceProvider
like
/**
* Register any events for your application.
*
* #return void
*/
public function boot()
{
FileLogs::observe(FileLogObserver::class);
}
ref link https://laravel.com/docs/8.x/eloquent#observers

Custom validation not calling the passes() function

I am trying to make a validation that will check whether at least one item is provided in an array following the steps in Custom Validation Rules
Routes.php
Route::middleware(['auth:api', 'bindings'])->group(function () {
Route::prefix('api')->group(function () {
Route::apiResources([
'exam-papers/{examPaper}/questions' => ExamPaperQuestionsController::class
]);
});
});
ValidateArrayElementRule.php
namespace App\Rules;
use Illuminate\Contracts\Validation\Rule;
class ValidateArrayElementRule implements Rule
{
public function __construct()
{
//
}
public function passes($attribute, $value)
{
echo "there";
return count($value) > 0;
}
public function message()
{
return 'At least one element is required!';
}
}
ExamPaperQuestionsController.php
public function store(ExamPaperQuestionStoreRequest $request, ExamPaper $examPaper)
{
return response()->json([])->setStatusCode(201);
}
In my test file I have
public function error_422_if_no_questions_provided()
{
Permission::factory()->state(['name' => 'create exam paper question'])->create();
$this->user->givePermissionTo('create exam paper question');
$this->actingAs($this->user, 'api')
->postJson('/api/exam-papers/' . $this->examPaper->id . '/questions', [])
->assertStatus(422);
}
ExamPaperQuestionStoreRequest.php
class ExamPaperQuestionStoreRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize()
{
return auth()->user()->can('create exam paper question');
}
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
echo "HERE";
return [
'questions' => [new ValidateArrayElementRule],
'questions.*.description' => 'required'
];
}
}
The test is failing
Expected status code 422 but received 201.
I can see the text "HERE" is logged but "there" is not. Why is my validation passes() function not being called?
Suppose if your request contain empty then it wont call custom validation. So you must add required filed to ensure request has key questions
'questions' => ["required",new ValidateArrayElementRule]
Incase questions is optional and if entered then at least two or three item required then you can use required if validation.
By default laravel support min in array
'questions' => ["required","array","min:1"]
why not to use the simple method in validation? :
$request->validate([
'title' => 'required|min:5|max:20',
'detail' => 'required',
'cat_image' => 'required',
]);

Laravel-5 redirect within authorize() function on form requests

Is it possible for me to create a redirect from within the authorize() function on a request? I have tried the following code, but it doesn't fulfill the redirect request. Can anyone shed any light on this?
Thanks.
<?php
namespace App\Http\Requests;
use App\Http\Requests\Request;
use App\Reserve;
use Cookie;
use Config;
class ClassVoucherCheckoutRequest extends Request
{
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize(Reserve $reserve, Cookie $cookie)
{
if((!$cookie->has(Config::get('app.cookie_name'))) || ($reserve->where('cookie_id', $cookie->get(Config::get('app.cookie_name')))->count() == 0))
{
return redirect()->to('butchery-voucher')->withErrors('Your reservation has expired. Places can only be held for up to 30 minutes.');
}
return true;
}
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
return [
];
}
}
I also have the same issue, I did not find any solution yet but I have do this by an another way, I know this is not the right solution but may be help for now.
My problem is: I need to register an user if any other user with same fb_id did not exists in database. But I was unable to check this condition because the middelware execute before the controller and it returns me the fb_id already taken error.
This is my UserController:
public function createUser (UserRequest $request) {
/** here I need to redirect user if the given `fb_id` is already exists
before it was always returning the `fb_id` exists error before executing
the following code, because all input filtered by the `UserRequest` middleware
I have changed the `UserRequest.php` to execute the following code.
**/
$fb_id = Input::get('fb_id');
$user = $this->user->getUserWhereFbIdIn([$fb_id]);
if(sizeof($user) > 0){
return Response::json(['result' => true, 'error' => false, 'message' => 'User exists', 'data' => $user]);
}
// insert user code is here
}
UserRequest.php:
public function authorize()
{
return true;
}
public function rules()
{
$fb_id = Input::get('fb_id');
$user = User::where('fb_id', $fb_id)->get()->toArray();
if(sizeof($user) > 0){
return [];
}
return [
'fb_id' => 'required|unique:users',
'username' => 'required|unique:users',
'email' => 'required|unique:users',
'image' => 'required',
'device_id' => 'required',
'status' => 'required',
];
}
I think the most elegant solution is to make the authorize() return false when you want to redirect, and override the forbiddenResponse() method on the FormRequest class. The drawback is that you'll either have to perform the condition logic twice, or set a state variable.
class MyRequest extends FormRequest
{
public function authorize(): bool
{
return Auth::user()->hasNoEmail() ? false : true;
}
public function forbiddenResponse(): Response
{
if Auth::user()->hasNoEmail() return redirect(route('user.should_provide_email'));
return parent::forbiddenResponse();
}
public function rules(): array
{
return [];
}
}
Of course, the argument could be made that such redirects should always take place in a middleware applied to specific groups of routes, but having the option to do it in a Request class can be nice.

Validating a Unique Slug on Update in Laravel 5

I currently have a model that has a text field and a slug field.
I validate that the slug is unique in my form request class:
public function rules()
{
return [
'name' => 'required|min:3',
'slug' => 'required|alpha_dash|unique:questions'
];
}
This works fine on create and properly denies the creation of duplicate slugs. However on my update method, it won't let me save a record because the slug already exists. Of course the slug does exist, but it exists on the record being edited, so I would like to continue to allow it to be saved. However, it should not be able to be changed to a slug on ANOTHER record.
Here's what my update ArticlesController method looks like:
public function update(Article $article, ArticleRequest $request)
{
$article->update($request->all());
return redirect('articles');
}
Is there a way to make this work in L5?
Try to modify your rule like following(in form request class):
public function rules()
{
return [
'name' => 'required,min:3',
'slug' => 'required|alpha_dash|unique:categories,slug,'.$this->id')
];
}
It works for me.
In unique rule you may specify id you want to ignore.
You can create 2 separate request (one for create and one for update), but you can do it also this way checking if if is set(I assume your update url looks like /questions/2 ):
public function rules()
{
$rules = [
'name' => 'required|min:3',
'slug' => ['required', 'alpha_dash']
];
$rule = 'unique:questions';
$segments = $this->segments();
$id = intval(end($segments));
if ($id != 0) {
$rule .= ',slug,' . $id;
}
$rules['slug'][] = $rule;
return $rules;
}
}
If you must have the ability to update a slug, projects I've worked on usually require it is not editable after creation, then you can use laravel's built in rule to ignore a certain record on the table by primary key.
$rules['slug'] = "required|unique:questions,slug,{$id}";
http://laravel.com/docs/5.0/validation
see "Forcing a unique rule to ignore a given ID"
In EditArticleRequest:
public function $rules ()
{
$id = $this->id;
return [
'name' => 'required|min:3',
'slug' => "required|alpha_dash|unique:articles,slug,$id",
];
}
Here is how I do it in Laravel 5.3 in details:
1- Create a new Form Request class by executing the next command in your terminal:
php artisan make:request ArticleFormRequest
Where ArticleFormRequest is the name of the form request class. This command will create a file called ArticleFormRequest.php in app/Http/Requests directory.
2- Open that created file and remove its content then place the next content in it:
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Http\Request;
use Illuminate\Validation\Rule;
use App\Article;
class ArticleFormRequest extends FormRequest
{
protected $rules = [
'name' => 'required|min:3',
'slug' => 'required|alpha_dash|unique:articles,slug',
];
// protected $user; // in case you want the current authenticated user
protected $request_method;
protected $id;
public function __construct(Request $request)
{
// $request->user() returns an instance of the authenticated user
// $this->user = $request->user(); // in case you want the current authenticated user
// $request->method() returns method of the request (GET, POST, PUT, DELETE, ...)
$this->request_method = strtoupper($request->method());
// segments(): Returns an array containing all of the segments for the request path
// it is important to assign the returned "segments" array to a variable first before using it, otherwise an error will occur
$segments = $request->segments();
// note this way will be valid only if "id" of the element is the last segment
$this->id = end($segments);
}
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
$rules = $this->rules;
if ($this->request_method == "POST") {
// do nothing..
} elseif (in_array($this->request_method, ["PUT", "PATCH"])) {
$article = Article::find($this->id);
if ($article) {
// forcing a unique rule to ignore a given id | https://laravel.com/docs/5.3/validation
$rules["slug"] = [
"required",
"alpha_dash",
Rule::unique("articles", "slug")->ignore($article->id, "id"),
];
// this is also can be used
// $rules['slug'] = "required|alpha_dash|unique:articles,slug,$article->id,id";
}
}
return $rules;
}
}
3- In your controller, you can use that ArticleFormRequest in store() and update() methods like this:
<?php
namespace App\Http\Controllers;
use App\Http\Requests\ArticleFormRequest;
class ArticlesController extends Controller
{
public function store(ArticleFormRequest $request)
{
// your code here..
}
public function update(ArticleFormRequest $request, $id)
{
// Your code here..
}
}
As already mentioned you can use the ignore feature in the validator functionality.
Just reference the id of the item you wish to ignore and make sure that when you update you use a patch request!
See more info here! http://laravel.com/docs/5.0/validation#rule-unique
protected $rules = [
'name' => 'required|min:3',
'slug' => 'required|alpha_dash|unique:questions'
];
public function rules()
{
$rules = $this->rules;
if ($this->isMethod('patch'))
{
$id = $this->articles;
$rules['slug'] = $rules['slug'].',slug,'.$id;
}
return $rules;
}

MongoDB only works when using fetch via other function

I am trying to get a record from my MongoDB. To get the record I use the following code;
public function getEventsForAggregate($identifier)
{
$events = $this->MongoCollection()->findOne([
'_id' => $identifier
], [
'events',
]);
var_dump($events);
}
Unfortunately it dies on the findOne.
Do I change the code so the findOne is in a protected function it does work.
So the following code does work.
public function getEventsForAggregate($identifier)
{
$events = $this->getEvents($identifier);
var_dump($events);
}
protected function getEvents($identifier)
{
return $this->MongoCollection()->findOne([
'_id' => $identifier
], [
'events',
]);
}
Can some one explain how it is possible that the first code breaks, but the second one works?
Extra code;
/** #var MongoCollection */
protected $mongoCollection;
public function __construct(MongoCollection $MongoCollection)
{
$this->mongoCollection = $MongoCollection;
}
/**
* #return MongoCollection
*/
protected function MongoCollection()
{
return $this->mongoCollection;
}

Categories