putting if statement in api with laravel - json

I'm currently learning on how API works and my mentor gave me a task to create submit the form using API and store the data on database with laravel and the task also require mandatory if logic on some field.
I have succeeded with the first task (storing data to the database ) and I'm having difficulties writing the mandatory if.
I'm confused, on my task paper I'm told to create one controller, one model and two endpoints (request-schedule and request-leaving) where each endpoint should have some parameters.
and for the request-leaving parameter, there are 10 parameters, 6 of them have this requirement like (mandatory if request type Request Day Off)
There are 3 requests typewritten on there
1. Request Day off
2. Request Schedule
3. Change Schedule
I'm a super newbie in programming, does anyone know how to solve this?
public function CreateReqSchedule(Request $request)
{
$reqschedule = new B777();
$reqschedule->reqtype = $request->input('reqtype');
$reqschedule->startdate = $request->input('startdate');
$reqschedule->enddate = $request->input('enddate');
$reqschedule->reason = $request->input('reason');
$reqschedule->route = $request->input('route');
$reqschedule->actualschedule = $request->input('actualschedule');
$reqschedule->changetoschedule = $request->input('changetoschedule');
$reqschedule->swapcrewid = $request->input('swapcrewid');
$reqschedule->swapcrewschedule = $request->input('swapcrewschedule');
$reqschedule->note = $request->input('note');
$reqschedule->save();
return response()->json($reqschedule);
}
code above is my only work, I'm feeling anxious, because I've googled it myself but I'm still stuck.

So you are talking about validations. you can put laravel validation into it like below
Use required validation for mandotory data and return response in json
// Making validation for fields
$validator = \Validator::make($request->all(), [
'fields1' => 'required',
'fields2' => 'required',
'fields3' => 'required',
]);
if ($validator->fails())
{
// return response on validaton fails
return response()->json(['status'=>400,'errors'=>$validator->errors()->all()]);
}
// If validation passes store your data in database

Related

How to implement Filtering on YII restful GET api?

I am working on Restful APIs of Yii.
My controller name is ProductsController and the Model is Product.
When I call API like this GET /products, I got the listing of all the products.
But, now I want to filter the records inside the listing API.
For Example, I only want those records Which are having a product name as chairs.
How to implement this?
How to apply proper filtering on my Rest API. I am new to this. So, I have no idea how to implement this. I also followed their documentation but unable to understand.
May someone please suggest me a good example or a way to achieve this?
First of all you need to have validation rules in your model as usual.
Then it's the controllers job and depending on the chosen implementation I can give you some hints:
If your ProductsController extends yii\rest\ActiveController
Basically the easiest way because almost everything is already prepared for you. You just need to provide the $modelClass there and tweak actions() method a bit.
public function actions()
{
$actions = parent::actions();
$actions['index']['dataFilter'] = [
'class' => \yii\data\ActiveDataFilter::class,
'searchModel' => $this->modelClass,
];
return $actions;
}
Here we are modifying the configuration for IndexAction which is by default responsible for GET /products request handling. The configuration is defined here and we want to just add dataFilter key configured to use ActiveDataFilter which processes filter query on the searched model which is our Product. The other actions are remaining the same.
Now you can use DataProvider filters like this (assuming that property storing the product's name is name):
GET /products?filter[name]=chairs will return list of all Products where name is chairs,
GET /products?filter[name][like]=chairs will return list of all Products where name contains word chairs.
If your ProductsController doesn't extend yii\rest\ActiveController but you are still using DataProvider to get collection
Hopefully your ProductsController extends yii\rest\Controller because it will already benefit from serializer and other utilities but it's not required.
The solution is the same as above but now you have to add it by yourself so make sure your controller's action contains something like this:
$requestParams = \Yii::$app->getRequest()->getBodyParams(); // [1]
if (empty($requestParams)) {
$requestParams = \Yii::$app->getRequest()->getQueryParams(); // [2]
}
$dataFilter = new \yii\data\ActiveDataFilter([
'searchModel' => Product::class // [3]
]);
if ($dataFilter->load($requestParams)) {
$filter = $dataFilter->build(); // [4]
if ($filter === false) { // [5]
return $dataFilter;
}
}
$query = Product::find();
if (!empty($filter)) {
$query->andWhere($filter); // [6]
}
return new \yii\data\ActiveDataProvider([
'query' => $query,
'pagination' => [
'params' => $requestParams,
],
'sort' => [
'params' => $requestParams,
],
]); // [7]
What is going on here (numbers matching the code comments):
We are gathering request parameters from the body,
If these are empty we take them from the URL,
We are preparing ActiveDataFilter as mentioned above with searched model being the Product,
ActiveDataFilter object is built using the gathered parameters,
If the build process returns false it means there is an error (usually unsuccessful validation) so we return the object to user to see list of errors,
If the filter is not empty we are applying it to the database query for Product,
Finally we are configuring ActiveDataProvider object to return the filtered (and paginated and sorted if applicable) collection.
Now you can use DataProvider filters just as mentioned above.
If your ProductsController doesn't use DataProvider to get collection
You need to create your custom solution.

Retrieve specific data using JSON decode Laravel

I'm new to Laravel. I need to retrieve specific data from the database using the JSON decode. I am currently using $casts to my model to handle the JSON encode and decode.
This is my insert query with json encode:
$request->validate([
'subject' => 'required|max:255',
'concern' => 'required'
]);
$issue = new Issue;
$issue->subject = $request->subject;
$issue->url = $request->url;
$issue->details = $request->concern;
$issue->created_by = $request->userid;
$issue->user_data = $request->user_data; //field that use json encode
$issue->status = 2; // 1 means draft
$issue->email = $request->email;
$issue->data = '';
$issue->save();
The user_data contains {"id":37,"first_name":"Brian","middle_name":"","last_name":"Belen","email":"arcega52#gmail.com","username":"BLB-Student1","avatar":"avatars\/20170623133042-49.png"}
This is my output:
{{$issue->user_data}}
What I need to retrieve is only the first_name, middle_name, and last_name. How am I supposed to achieve that? Thank you in ADVANCE!!!!!
As per the above code shown by you it will only insert data into the database.For retrieving data you can make use of Query Builder as i have written below and also you can check the docs
$users = DB::table('name of table')->select('first_name', 'middle_name', 'last_name')->get();
I will recommend using Resources. It really very helpful laravel feature. Check it out. It is a reusable class. You call anywhere and anytime.
php artisan make:resource UserResource
Go to your the newly created class App/Http/Resources/UserResource.php and drfine the column you want to have in your response.
public function toArray($request) {
return [
"first_name" => $this->first_name,
"middle_name" => $this->middle_name,
"last_name" => $this->last_name
]
}
Now is your controller you can use the UserResource like folow:
public function index()
{
return UserResource::collection(User::all());
}
Or after inserting data you can return the newly added data(f_name, l_name...)
$user = new User;
$user->first_name= $request->first_name;
$user->middle_name= $request->middle_name;
$user->last_name= $request->last_name;
$user->save();
$user_data= new UserResource($user);
return $user_data;

Unit Testing Laravel need help on how to pass my variables properly

So I'm getting into Unit Testing and I have created a test for creating and adjustment line in my DB. Here is the code:
$response = $this->json('POST', '/quotes/3/adjustment',
[
'adjustments' => array([
'description' => 'TEST-Description',
'amount' => 1000,
'quote_id' => 3
])
]
);
$response->assertStatus(201);
When creating it hits my controller then an instance of my Adjustment model is created, and in that model I have this code for the creating of it:
foreach($request->adjustments as $adjustment) {
if(array_key_exists('id', $adjustment)) {
$this->find($adjustment['id'])->update([
'description' => $adjustment['description'],
'amount' => $adjustment['amount'],
'quote_id' => $quote->id
]);
} else {
$this->create([
'description' => $adjustment['description'],
'amount' => $adjustment['amount'],
'quote_id' => $quote->id,
]);
}
}
return $quote;
So it expects adjustments to be an array and I thought I had it coded properly in the test but i get back a 200 response, which is not the 201 as expected. Any ideas on how to properly pass the single array in my test file so that it passes the test?
Here is my controller:
$adjustment = new Adjustment();
return $adjustment->newAdjustment($quote, $request)->adjustments;
On a side note if I run this in postman as raw JSON(applicatoin/json) it creates the resource in the DB:
{
"adjustments": [{
"description": "testing-postman",
"amount": 1000,
"quote_id": 1
}
]
}
As of Laravel 5.6, if you return a newly created model from your controller, Laravel will automatically set the response status to a 201. This typically is what you would do when building an API that follows RESTful practices.
However that may not suit your case as you may need to return other data from your controller and not just the newly created model and if so, I believe Laravel will return a 200 instead.
So you have a few of options:
In your controller you could force the 201 with return response($myData, 201);
Return only the newly created model and nothing else.
Or just have your test do the following:
$response->assertStatus(200);
$this->assertDatabaseHas('adjustments', $adjustment->toArray());
With the third option, your test is verifying that everything went okay and that the actual model was created and exists in the database (you'll need to adjust it based on your needs).
More info on the Laravel 5.6 201 response: https://laravel.com/docs/5.6/upgrade - Search on the page for: Returning Newly Created Models

RedBean PHP credit card number issue

I have started using Redbean PHP recently. So I am not much aware of how it deals things.
Until now I love how simple it is making things for me. But I have ran into quite an issue today. I need to store credit card numbers into a table. But as soon as I store the bean, the card number gets changed into a float(decimal) kind of value.
'1234123412341234' is getting stored as '1.234123412341234e15'
The datatype is 'double' created by redbean, but I gave as a string. This is kind of weird for me I am not much of an expert in either SQL or PHP. Is there a way to override how redbean creates table. So someone please help me. Am I missing something here. The following is my corresponding code and the framework used is Codeigniter.
Data Variable
$data = array(
'card_name' => 'Shiva Kumar Avula',
'card_no' => '1234123412341234',
'card_issuer' => 'Visa',
'card_cvv' => '123',
'card_exp_month' => 12,
'card_exp_year' => 2020
);
$card = $this->card_model->create_card($data, TRUE); // Making it primary
Model Function
public function create_card($data, $is_primary = FALSE)
{
$card = R::dispense('card');
$card->name = $data['card_name'];
$card->number = $data['card_no'];
$card->issuer = $data['card_issuer'];
$card->cvv = $data['card_cvv'];
$card->exp_month = $data['card_exp_month'];
$card->exp_year = $data['card_exp_year'];
$card->is_primary = $is_primary;
$card->is_verified = 0;
$card->ts_created = $this->ts_sql;
$card->ts_modified = $this->ts_sql;
$id = R::store($card);
}
Snapshot of my output in phpmyadmin,
Snapshot that shows the datatype,
You can set the beans meta property for number to string.
$card->setMeta("cast.number", "string");
This will save any values of $card->number as varchar.
See RedBean Internals for more information.

How to do Kohana Validation of $_serialize_column inside ORM

The validation on Kohana ORM is done using rules
function rules()
{
return array(
'username' => array(
array('not_empty'),
array(array($this, 'availability')),
)
);
}
I'm struggling to validate a JSON encoded column using $_serialize_columns.
class Model_Admin extends ORM {
protected $_belongs_to = array();
protected $_has_many = array(
'plans' => array(),
'groups' => array(),
'transactions' => array(),
'logins' => array()
);
protected $_serialize_columns = array('data');
/**
* #param array $data
* #param Validation $validation
*
* #return bool
*/
public function data($data, $validation)
{
return
Validation::factory(json_decode($data, TRUE))
// ... rules ...
->check();
}
public function rules()
{
return array(
'data' => array(
array(array($this, 'data'), array(':value',':validation')
)
);
}
}
the array that gets encoded is:
array(
'name' => '',
'address' => '',
'phone' => '',
'postalcode' => ''
);
the data method receives the json encoded data, because the ORM runs the filters before doing the validation, so I need to convert it back to an associative array, then create a new validation object to check specifically for the content of that array. Because I can't merge Validation rules from another Validation instance
Updated Answer
The use of a second validation object is necessary since save() causes the internal model validation object to be checked. This means that rules added to the validation object being checked from a validation rule will be ignored (Validation->check() imports the rules into local scope before looping).
Since the data itself is technically another object (in the sense of object relationships, it has its own dataset that needs validation) the ideal solution would be to find a way to create a real model that saves the data.
There are numerous other benefits to saving data with proper database column definitions, not least if you need to perform data property lookups, make in-situ changes etc. (which would otherwise require unserializing the data column, potetnailly in all rows).
There are some alternatives, but they feel like kludges to me:
Create a model that represents the data object and add rules to it, using check() to validate the data (problem: will require a lot of maintenance, no real-world table means columns must be manually defined).
Set the data as real columns in the Admin model, and use a filter that will convert it into the data column on set (problem: again, must manually define the columns and exclude the additional columns from the save operation).
I hope this is of some use.
Original Answer
The Kohana ORM save() method permits the inclusion of an "extra" validation object, which is merged into the main ORM validation object namespace.
This is documented briefly here.
If I have understood correctly, I think you are looking to do something like this:
// another script, e.g., a controller
// Create the model
$admin = ORM::factory('Admin');
// $data = the data as an array, before serialization ...
$extra_validation = Validation::factory($data)
// add ->rule() calls here, but DO NOT chain ->check()
;
// Set $data in the model if it is going to be saved, e.g., $admin->data = $data;
// Set other data... e.g., $admin->foo = 'bar';
// Save the model
try {
$admin->save($extra_validation);
}
catch (ORM_Validation_Exception $e)
{
// Manipulate the exception result
}
While in this example you must still create another validation object, you are now able to catch all exceptions in a single block. I would recommend using var_dump() or similar on $e->errors() to check the namespace if you are using i18n messages to provide a human-readable error message. You should find that a namespace called "_external" has been created in the response.