How to Mock a Guzzle Request for PHPUnit - laravel-5

I have a class like this:
class CategoryClient
{
private $categories;
/**
* Constructor
* Retrieves JSON File
*/
public function __construct(Client $client)
{
$response = $client->request('GET', config('services.url'));
$this->categories = collect(json_decode($response->getBody(), true));
}
}
How would I mock the json response for testing purposes in PHPUnit? and set the $this->categories variable?

You can use the Mock Handler of the Guzzle testing strategy and instantiate your Client class. As example:
$mock = new MockHandler([
new Response(200, [], '{
"categories": [
{ "id" : 1,
"name": "category name 1"},
{ "id" : 2,
"name": "category name 3"},
]
}');
$handler = HandlerStack::create($mock);
$guzzleClient= new Client(['handler' => $handler]);
$categoryClient = new CategoryClient($guzzleClient);
Hope this help

Related

Laravel - Json object showing empty ParameterBag

I have this JSON data sent in HTTP body in a post request.
{
"id" : 238,
"title": "Its a title",
"description": "Its a description",
"target_price": 3000,
"date_of_availability": "16-02-2023",
"condition": "abc",
"latitude": "-31.953030",
"longitude": "115.853600",
"attributes": {
"list" : [
{
"title" : "Color",
"value" : "Red"
},
{
"title" : "Frame",
"value" : "Metal Frame"
}
]
}
}
I want attributes to be stored in json data type field. I can get value of all other fields in my controller but when i dd($request->attributes); it show me empty Parameter Bag.
How can i get $request->attributes and store it in my json data type field of mysql.
This is my migration
public function up()
{
Schema::create('posts', function (Blueprint $table) {
$table->id('post_id')->generatedAs();
$table->string('title');
$table->text('description');
$table->integer('target_price')->nullable();
$table->date('date_of_availability')->nullable();
$table->string('condition')->nullable();
$table->decimal('latitude', 11, 8);
$table->decimal('longitude', 11, 8);
$table->json('attributes')->nullable();
$table->timestamps();
});
}
Here i am saving
$post = new Post();
$post->title = $data->title;
$post->description = $data->description;
$post->target_price = $data->target_price;
$post->date_of_availability = date("Y-m-d", strtotime($data->date_of_availability));;
$post->condition = $data->condition;
$post->latitude = $data->latitude;
$post->longitude = $data->longitude;
$post->attributes = $data->attributes;
$post->save();
This is the error i am getting for line $post->attributes = $data->attributes;
"message": "Object of class Symfony\Component\HttpFoundation\ParameterBag could not be converted to string",
The Laravel request object uses magic methods to access the parameters that are passed in the body of the request. This only works if the Request class doesn't already have a property of the same name.
The Illuminate\Http\Request class extends the Symfony\Component\HttpFoundation\Request class which has an explicit property called $attributes:
/**
* Custom parameters.
*
* #var ParameterBag
*/
public $attributes;
If you want to explicitly get a property from the request body without using the magic method you can use the input or json methods:
$post->attributes = $request->json('attributes');

Laravel store JSON data API to database

I got the data json from API and I want to store them to my database.
data json sample :
{
"success": true,
"data": [
{
"status_employee_id": "1",
"name": "Manager"
},
{
"status_employee_id": "2",
"name": "Staff"
},
{
"status_employee_id": "3",
"name": "OB"
},
{
"status_employee_id": "4",
"name": "Fired"
},
{
"status_employee_id": "5",
"name": "Retired"
}
]
}
My model
class StatusEmployee extends Model
{
use HasFactory;
protected $table = 'status_employee';
protected $fillable = [
'status_employee_id','name'
];
public $timestamps = false;
}
I have tried use this in my controller
public function store()
{
$client = new \GuzzleHttp\Client();
$res = $client->request('GET', 'http://xx.xx.xx.xx/tools/public/get_status_employee');
$datas = json_decode($res->getBody(), true);
foreach($datas as $data){
StatusEmployee::create([
'status_employee_id' => $data->status_employee_id,
'name' => $data->name,
]);
}
}
And I want to store the data json sample to my table status_employee. How to make it?
It's easy, Laravel Eloquent will do everything for you.
// If json is in string decode first
$data = json_decode($res->getBody(), true); // to array
// Eloquent approach
StatusEmployee::insert(#$data['data']);
I assume you use Laravel since you have mentioned Laravel in your tags.
DB::table('status_employee')->insert(json_decode($res->getBody(),true)['data']);

Laravel - How to consume and refresh external api into db using Guzzle

I am having this model in my Laravel-5.8 project:
Employee
class Employee extends Model
{
protected $table = 'employees';
protected $primaryKey = 'id';
protected $fillable = [
'staff_code',
'first_name',
'last_name',
'department_id',
];
public function department()
{
return $this->belongsTo('App\Department','department_id');
}
}
That is,:
App\Employee
Also I have an external api that comes in form of JSON get request.
https://api.employees.net/allemployees
I have viewed it with postman get request and I have something like this:
{
"ID": "1",
"StaffCode": "STC001",
"FirstName": "Japheth",
"LastName": "Shalom",
"DepartmentCode": "dep2",
},
{
"ID": "2",
"StaffCode": "STC002",
"FirstName": "Ahitophel",
"last_name": "Nedum",
"DepartmentCode": "dep1",
},
{
"ID": "3",
"StaffCode": "STC003",
"FirstName": "Joash",
"FirstName": "Nathan",
"DepartmentCode": "dep2",
},
and so on... this continues
Already I have created this function:
use App\Employee;
use App\Department;
public function index()
{
$client = new GuzzleHttp\Client();
$res = $client->request('GET','https://api.employees.net/allemployees');
$clientdatas = json_decode($res, true);
...
}
Apart from the id and staff_code that are UNIQUE, any of the others fields too can change from the source.
Since any of the fields can change at any time. How do I refresh the entire db, save new data and update changes?
Thank you
I could do something like this:
use App\Employee;
use App\Department;
public function index()
{
$client = new GuzzleHttp\Client();
$res = $client->request('GET','https://api.employees.net/allemployees');
$clientdatas = json_decode($res->getBody()->getContents(), true);
foreach($clientdatas as $clientdata)
{
$employee = Employee::firstOrNew(['id' => $clientdata['ID']]);
$employee->staff_code = $clientdata['StaffCode'];
$employee->first_name = $clientdata['FirstName'];
$employee->last_name = $clientdata['LastName'];
$employee->save();
}
}
Every time you will make an API call, create an instance of the employee model, or get the associated model if the ID exists. Then assign the new values and save your model. This way, you will be able to either create or update the models in a single loop without any complexities.
Don't know will it work or not but the logic you can keep.. In the other answer he is querying under a loop which is bad!
Hope It will Help you a little bit
public function index() {
$client = new GuzzleHttp\Client();
$res = $client->request('GET','https://api.employees.net/allemployees');
$clientdatas = json_decode($res->getBody()->getContents(), true);
// create a blank array for insert
$insert_arr = [];
foreach($clientdatas as $clientdata) {
$make_array = [
'id' => $clientdata['ID'],
'staff_code' => $clientdata['StaffCode'],
'first_name' => $clientdata['FirstName'],
.
.
];
array_push($insert_arr, $make_array);
// Now the the $insert_arr will ready for insert
}
// Here you have to check its duplicate or not
$exist_in_db = Employee::all('id')->toArray(); // get the id array from db
// do the stuff for unset the duplicate
$final_id = array_map(function($value) {
return $value['id'];
}, $team_id);
unset($exist_in_db);
if(count($final_id) > 0){
foreach ($insert_arr as $key => $value) {
if (in_array($value['id'], $final_id)) {
unset($insert_arr[$key]);
} else {
array_push($final_id, $value['id']);
}
}
}
// finally insert it here
if (count($insert_arr) > 0) {
Employee::insert($insert_arr);
}
}
Let me know its helpful or not!

laravel - change value in array for API Resources

{
"data": {
"username": "candy",
"certificates": [
{
"id": 11,
"category_id": 1,
"certname": "cert name test",
"created_at": "2018-08-18 00:58:12",
"updated_at": "2018-08-18 00:58:12"
}
]
}
}
Above is a response by using Eloquent: API Resources.
I would like to put category name instead of category_id.
Below is resource class
public function toArray($request)
{
return [
'nickname' => $this->nickname,
'certificates' => $this->certificates,
];
}
certificates are in array (hasMany relationship)
certificates belongsTo category
In this case, in the resource class you can fetch category name for each certificate and attach it.
public function toArray($request)
{
$certificateList = $this->certificates;
foreach($certificateList as $ceritificate) {
// fetch only the category name from the database.
// attach to the certificate.
$categoryName = Category::where('id', $certificate->category_id)->pluck('name')->first();
$certificate->setAttribute('category_name, $categoryName);
}
// then as usual
return [
'nick_name' => $this->nick_name,
'certificates' => $certificateList
];
}
This Might Help,
Run a foreach loop
$category = "Your SELECT Query";
foreach ($category as $value) {
$categoryId = json_decode($value->category_id);
$x = Category::select('certname')->whereIn('id', $categoryId)->get();
foreach ($x as $as) {
$y[] = $as->certname;
}
$value->certname = $y;
you can just do it like this
in controler
return CertificateResource::collection(Certificate::with('category')->get());
in CertificateResource
return [
'nickname' => $this->nickname,
'certificates' => $this->certificates,
'category_name'=>$this->whenLoaded('category', function () {
return $this->category->category_name;
}),
];

Laravel API - Vue.js returning Posts with user

I am trying to learn Vue.js that consumes an API build with Laravel. The idea is simple, a user can make a post and a post can have comments. I can get the relationships working within laravel, but I can not figure out how to return the author name of the post or comment with Vue.js.
When using the blade templating engine I use something like this in a foreach loop for returning the Author name:
{{ $post->user->name }}
When I return the posts trough an API I get don't get any user information, except for the user id. How can I get the user information that belongs to this post?
{
"message": "Success",
"data": [
{
"id": 1,
"body": "test body 1",
"user_id": "1",
"created_at": "2016-09-16 10:22:57",
"updated_at": "2016-09-16 10:22:57"
}
]
}
<script>
export default {
/*
* The component's data.
*/
data() {
return {
posts: [],
};
},
/**
* Prepare the component.
*/
ready() {
this.getPosts();
},
methods: {
/**
* Get Posts.
*/
getPosts: function() {
this.$http.get('/api/wall/posts')
.then(response => {
this.posts = response.data.posts;
});
}
}
}
</script>
public function getPosts($id = null)
{
if (!$id){
$data = Post::all();
$message = 'Success';
$code = 200;
} else {
$data = Post::FindOrFail($id);
$message = 'Success';
$code = 200;
}
return Response::json(['message' => $message, 'data' => $data], $code);
}
You may use eager loading for that:
Post::with('user')->FindOrFail($id);

Resources