I am trying to test a JSON API following the officiel doc. I know the problem comes from the data array given to the POST request. The test works fine with a single level array like ['hello' => 'world'], so apparently the post function cannot handle complex structures ? What am I doing wrong here ?
Test:
public function testInsert()
{
$this->post(
'/test',
[
'content' => 'Hello world!',
'count' => [
'a' => 12.345678,
'b' => 12.345678
],
'user' => [
'id' => 1
]
],
['contentType' => 'application/json']
)->seeJsonEquals([
'status' => true
]);
}
Error:
unknown:myapp nobody$ phpunit
PHPUnit 4.8.24 by Sebastian Bergmann and contributors.
E.
Time: 648 ms, Memory: 15.25Mb
There was 1 error:
1) APITest::testInsert
ErrorException: Invalid argument supplied for foreach()
/Users/nobody/myapp/vendor/laravel/framework/src/Illuminate/Support/Arr.php:487
/Users/nobody/myapp/vendor/laravel/framework/src/Illuminate/Foundation/Testing/Concerns/MakesHttpRequests.php:231
/Users/nobody/myapp/tests/APITest.php:43
FAILURES!
Tests: 2, Assertions: 2, Errors: 1.
Controller:
public function store() {
$user = User::find(Input::get('user.id'));
// TODO: Validate input using JSON schema
if (empty($user))
$errors[] = 'User does not exist.';
if (empty(Input::get('content')))
$errors[] = 'Content is empty.';
$a = Input::get('location.latitude');
if ($a < 15)
$errors[] = 'A out of range.';
$b = Input::get('location.longitude');
if ($b < 20)
$errors[] = 'B out of range.';
if (empty($errors)) {
$post = new Post();
$post->content = Input::get('content');
$post->count()->create([
'a' => $a,
'b' => $b
]);
$user->posts()->save($user);
$post->save();
return APIUtils::makeStatusResponse(true);
}
return APIUtils::makeStatusResponse(false, $errors);
}
I re-installed my Laravel application using the laravel new myapp command and everything works fine now. I am assuming the problem was coming from the previous install made with composer create-project --prefer-dist laravel/laravel may.
Related
does not pass me the last test that compares the field just entered with the one sent because json
I have the following fields:
public function up()
{
Schema::create('polls', function (Blueprint $table) {
$table->id();
$table->text('now');
$table->json('paramJson');
$table->enum('status', ['a', 'b', 'c','d'])->default('a');
});
}
Poll model:
protected $fillable=[
'now',
'paramJson',
];
//to cast that column from JSON to an array automatically (maybe it doesn't work)
protected $casts = [
'paramJson' => 'array',
];
PollsController.php
public function add(Request $request)
{
$poll = Poll::create($request->all());
return response()->json($poll, 201);
}
Feature/PollApiTest.php
$data = [
"now" => "Will Messi sign for City?",
"parameters" : {"a"=> "yes", "b"=> "no"},
];
$response = $this->post('/api/polls',$data);//add data in polls
$response ->assertStatus(201);// assert Ok
$response->assertJson($data);//assert Ok
$response = $this->get('/api/poll');//get index polls
$this->assertSame($dataDbTest[0]['paramJson'],$data['paramJson']);//this test fails
the last test fails because below the error
Failed asserting that Array &0 (
'a' => 'yes'
'b' => 'no' ) is identical to '{"a": "yes", "b": "no"}'.
if the last test I do it with json_encode:
$this->assertSame($dataDbTest[0]['paramJson'],json_encode($data['paramJson']));
--- Expected
+++ Actual ## ##
-'{"a": "yes", "b": "no"}'
+'{"a":"yes","b":"no"}'
I think this should be the case
$this->assertSame(json_decode($dataDbTest[0]['paramJson']),$data['paramJson']);
json_decode
i want to generate reports from api external, using guzzle, here is my result
{#430 ▼
+"data": {#427 ▼
+"report_id": "20190801-5f6e21a5"
+"status": 5
+"creation_date": "2019-08-01 13:19:49"
+"due_date": "2019-08-02 13:19:49"
+"data": {#432 ▼
+"chassis_number": "ACR50-0183692"
+"engine": "2AZFE"
+"manufacture_date": "2014-07"
+"registration_date": "2019-04-17"
+"make": "TOYOTA"
+"model": "ESTIMA"
+"displacement": "2360"
+"fuel": "GASOLINE"
}
}
+"error": ""
}
but i dont know how to get the value from this json and save to database. i want to save value from report_id, status, creation date etc
$client = new Client();
$body = $client->request('GET', 'https://xxxxx/api/v1/get-report', [
'headers' => [
'Accept' => 'application/json',
'Carvx-User-Uid' => 'xxxxxx',
'Carvx-Api-Key' => 'xxxxxx',
'needSignature' => '0',
'raiseExceptions' => '1',
'isTest' => '0'
],
'query' => [
'report_id' => $reportId,
'true'=>'1'
]
])->getBody();
$contents = (string) $body;
$data = json_decode($contents);
// dd($data);
//to get value from status
$var_status = var_export($data['status'],true);
$status = substr($var_status, 1, -1);
echo $status;
and i get this error
Cannot use object of type stdClass as array
json_decode by default returns a Stdclass object, with properties representing the keys in the json object.
You can tell json_decode to return an associative array instead by passing true as the second param:
json_decode($contents, true); // returns array
Docs: https://www.php.net/manual/en/function.json-decode.php
I'm using Laravel 5.7. and GuzzleHttp 6.0 to get API response
from endpoint
I'm passing query data from Blade form to this function.
public static function prhmulti($multisearch, $start ,$end)
{ $city = $multisearch['city'];
$client = new Client([
'base_uri' => 'https://avoindata.prh.fi/tr/',
'query' => [
'totalResults' => 'true',
'maxResults' => '1000',
'registeredOffice'=> $city,
'companyForm'=>'OY',
'companyRegistrationFrom'=>$start,
'companyRegistrationTo'=>$end,
],
'defaults'=>[
'timeout' => 2.0,
'cookies' => true,
'headers' => [
'content-type' => 'application/json',
'User-Agent' =>"GuzzleHttp/Laravel-App-5.7, Copyright MikroMike"
]]]);
$res = $client->request('GET','v1');
$ResData = json_decode($res->getBody()->getContents());
dd ($ResData) gives all data from API response.
But I am not able to return JSON back to other function
return $this->multisave($ResData);
public static function multisave (data $ResData)
This will parse JSON and
{
foreach ($data->results as $company) {
$name = $company->name;
$Addr = $company->addresses;
$businessId = $company->businessId;
$companyForm = $company->companyForm;
$registrationDate = $company->registrationDate;
foreach ($company->addresses as $Addr) {
$city = $Addr->city;
$postcode = $Addr->postCode;
$street = $Addr->street;
}
}
save data to Mysql.
$NewCompany = new Company();
$NewCompany = Company::updateOrCreate($array,[
[ 'vat_id', $businessId],
[ 'name', $name],
[ 'form',$companyForm],
[ 'street', $Addr],
[ 'postcode', $postcode],
[ 'city', $city],
[ 'regdate', $registrationDate],
]);
}
IF Parse part and Save part is inside same function code works ok(save only one company),
but I need to separate them because later on it's easier to maintain.
Error which I am getting to return $ResData
" Using $this when not in object context"
Information is in JSON array.
Also foreach part save ONLY one company ?
foreach ($data->results as $company) {
$name = $company->name;
$Addr = $company->addresses;
$businessId = $company->businessId;
$companyForm = $company->companyForm;
$registrationDate = $company->registrationDate;
foreach ($company->addresses as $Addr) {
$city = $Addr->city;
$postcode = $Addr->postCode;
$street = $Addr->street;
}
So : 1) What is best way to create own function for parse JSON
and other for save data to DB?
2) As foreach loop save only one company data, What is
best way to fix it?
Thanks MikroMike.
Resolved my own question for saving companies to db
First get total number inside Array
use for-loop to make counting
use foreach-loop extract information per single company as object.
$data = json_decode($res->getBody()->getContents());
$total = $data->totalResults;
for ($i = 0; $i < $total; $i++){
$NewCompany = new Company();
foreach ($data->results as $company)
{
$name = $company->name;
$businessId = $company->businessId;
$companyForm = $company->companyForm;
$registrationDate = $company->registrationDate;
$array = [];
Arr::set($array, 'vat_id', $businessId);
Arr::set($array, 'name', $name );
Arr::set($array, 'form', $companyForm);
Arr::set($array, 'regdate', $registrationDate);
$NewCompany = Company::updateOrCreate($array,[
[ 'vat_id', $businessId],
[ 'name', $name],
[ 'form',$companyForm],
[ 'regdate', $registrationDate],
]);
}// END OF MAIN FOREACH
}// END OF For loop
}// END OF FUCNTION
} // END OF CLASS
I have a situation where a user uploads his/her trip photos. They are saved in a folder and also supposed to be in database. Situation is: my code is working perfectly on localhost, and many other servers, but not on the server I want. Though it uploads files successfully, but the query is not executed which is supposed to save file path in database. I am stuck in this problem from more than a week. The same code works in other places. Here is my controller:
public function trip_photos(){
$this->load->model('UserModel');
$this->load->model('CommentModel');
$this->load->library('session');
print_r($_FILES);
$logged_session = $this->session->userdata('login');
if($logged_session == 1) {
$this->load->model('TripModel');
$this->load->model('UserActivityModel');
$uid = $this->session->userdata('uid');
$tid = $this->input->post('tid');
foreach($_FILES as $key => $image_upload){
$upload = self::upload_trip_photo($key);
if($upload['status']){
$this->TripModel->add_trip_photo($uid, $tid, $upload['file']);
}
}
$this->UserctivityModel->add_user_photo($uid, $tid);
}else{
redirect('/');
}
}
private function upload_trip_photo($image){
$msg = '';
$config['upload_path'] = './assets/images/trip/';
$config['allowed_types'] = 'gif|jpg|png';
$config['max_size'] = 2048;
$config['file_name'] = parent::getGUID();
$this->load->library('upload', $config);
if ($this->upload->do_upload($image))
{
$data = $this->upload->data();
$resize['image_library'] = 'gd2';
$resize['source_image'] = "./assets/images/trip/" . $data['file_name'];
$resize['create_thumb'] = TRUE;
$resize['maintain_ratio'] = TRUE;
$resize['width'] = 222;
$resize['thumb_marker'] = '';
$resize['new_image'] = "./assets/images/trip/thumbnails/" . $data['file_name'];
$this->image_lib->resize();
$this->image_lib->clear();
$this->image_lib->initialize($resize);
if($this->image_lib->resize()){
$status = true;
$msg = $data['file_name'];
}else{
$status = false;
}
}
else
{
$status = false;
}
#unlink($_FILES[$image]);
return array('status' => $status, 'file' => $msg);
}
when I enabled CI_Profiler, it says that only 2 out of 3 query executed on the server I want it to work. But the same profiler suggests that 3 of 3 queries executed on localhost or other servers. Its so confusing.
Please note that I already have checked the following:
File Upload: On
upload_raw_post_data: On
selinux permissions: disables (mine is centos)
File permissions: 777
php memory_limit: 128 MB
max_size: 8 MB
var_dump, print_r, echo all not working or displaying any information from controller.
somehow, this in above code: $upload = self::upload_trip_photo($key); is not giving it back the file path it requires. Can anybody help please? #DFriend
UPDATED Turns out that in the localhost are other servers where its working, this array is returned by the function upload_trip_photo to the $upload variable:
Array ( [image0] => Array ( [name] => maintour3.jpg [type] => image/jpeg
[tmp_name] => D:\xampp\tmp\php2539.tmp [error] => 0 [size] => 200491 ) )
array(2) { ["status"]=> bool(true) ["file"]=> string(36)
"E3965DFC8B265CEFF522A1EC43B33E34.jpg" }
while in the server where its not working, only this array is returned:
Array ( [image0] => Array ( [name] => mg7.jpg [type] => image/jpeg
[tmp_name] => /tmp/phpNcCnX0 [error] => 0 [size] => 28460 ) )
It means this statement in the upload_trip_photo() function:
return array('status' => $status, 'file' => $msg);
is not returning the requested array, with file name and status. And why? I am totally clueless.
Help Please!
Thankfully this worked after extensive debugging. The line
if($this->image_lib->resize()){
$status = true;
$msg = $data['file_name'];
}else{
$status = false;
}
was not working. Later when I set it to display_error() method, it showed that my server did not support GD library. This is an essential library to manipulate Graphics. So, the query was not being executed, as the $status variable was set to false.
I recompiled my php with GD Library module. And bigno! its working now.
Thanks for staying with me. :)
I'm trying to build the right response function in my moodle webservice.
I printed the php structure of my json response:
[
{
"name":"Quiz",
"id":"1",
"theme":"green",
"quizzes":[
{
"type":"single-select-item",
"question":"Question example 1?",
"options":[
"<p>answer1<br><\/p>",
"<p>answer2<br><\/p>",
"<p>answer3<br><\/p>",
"<p>answer4<br><\/p>"
],
"answer":"1"
},
{
"type":"single-select-item",
"question":"<p>Question example 1?<br><\/p>",
"options":[
"<p>answer1<br><\/p>",
"<p>answer2<br><\/p>",
"<p>answer3<br><\/p>",
"<p>answer4<br><\/p>"
],
"answer":"2"
}
]
}
]
but I can't write the right return function for moodle webservices .
I have written the return funtion as following
return new external_multiple_structure(
new external_single_structure(
array(
"name"=> new external_value(PARAM_TEXT, 'quiz name'),
"id"=> new external_value(PARAM_TEXT, 'quiz id'),
"theme"=> new external_value(PARAM_TEXT, 'quiz theme'),
"quizzes" => new external_multiple_structure(
new external_single_structure(
array(
"type" => new external_value(PARAM_TEXT, 'answer type'),
"question" => new external_value(PARAM_TEXT, 'question'),
"options" => new external_multiple_structure(
new external_value(PARAM_TEXT, 'options')
),
"answer" => new external_value(PARAM_TEXT, 'right answer')
)
)
)
)
)
);
but I still receive the following exception. What's wrong in my return function?
{"exception":"invalid_response_exception","errorcode":"invalidresponse","message":"Invalid response value detected"}
any suggestion?
thank you
I just found the problem!!
The return function is correct but I receive exception because some text inside the structure contains HTML tags like and escape characters that break the return function composition.
Finally I used this PARAM_RAW instead of PARAM_TEXT and it works like a charm!