I'm new in Silex and I'm trying to retrieve nested Json Data with POST. Here is the Json part.
{
"action": "opened",
"number": 3,
"pull_request": {
"id": 35845110,
"number": 3,
"state": "open",
"locked": false,
"title": "Kie"
}
}
My code works for action, number and pull_request but I only want to use the data state in pull_request and I don't know how to collect it.
$app->before(function (Request $request) {
if (0 === strpos($request->headers->get('Content-Type'), 'application/json')) {
$data =json_decode($request->getContent(), true);
$request->request->replace(is_array($data) ? $data : array());
}
});
$app->post('/api', function(Request $request) use ($app) {
$pullRequest = array(
'action' => $request->request->get('action'),
'number' => $request->request->get('number'),
'pull_request' => $request->request->get('pull_request'),
'state' => $request->request->get('state')
);
return $app->json($pullRequest,201);
});
Thanks for your help
It's quite simple actually. After you decode your json object, pull_request becomes an array, and therefore if you want to access state you need to refer to pull_request first. One way would be the so called array dereferencing, like this:
'state' => $request->request->get('pull_request')['state']
but in order to use that syntax, your version of PHP must be at least 5.4.
You can also assign pull_request to a variable and use it like any other array up until now.
$pullRequest = $request->request->get('pull_request');
//....
'state' => $pullRequest['state']
Related
I want to send request via post method with API, and when sending values, sometimes I need to send two values instead of one, and for this I need to loop it. The solution to this is, before sending the request, I save it to the array in the loop and try to complete the process by making json_encode.
My explanation may not be fully explanatory, so I will explain through the codes.
The request I want to throw is normally like this:
CURLOPT_POSTFIELDS =>'
[
{
"items":
[
{
"name":"string",
"sku":"string",
}
],
}
]'
But some times the items value needs to have two instead of one. For example:
CURLOPT_POSTFIELDS =>'
[
{
"items":
[
{
"name":"string",
"sku":"string",
},
{
"name":"string",
"sku":"string",
}
],
}
]'
So before i make this request i am saving these values to array in a foreach loop.
$data =array();
foreach ($request->orderItems as $orderItemId) {
$order_item = OrderItem::where('orderItemId',$orderItemId)->first();
$data[] = array(
"sku"=> $order_item->sku,
"name"=> $order_item->name,
)
}
And if I'm going to send more than one value, my final code looks like this.
CURLOPT_POSTFIELDS =>'
[
{
"items": '.json_encode($data).',
}
]'
Here is where the problem starts and when i try to send this request i get this error:
Array to string conversion
What should I do exactly? Where am I missing?
You might be missing the Content-Type header for your cURL call.
CURLOPT_HTTPHEADER => [
'Content-Type' => 'application/json',
],
Try to encode all the content in CURLOPT_POSTFIELDS like this way
$array = [
array(
"name" => "string",
"sku" => "string",
),
array(
"name" => "string",
"sku" => "string",
)
];
$final = json_encode([["items" => $array]]);
//now use this variable directly in CURLOPT_POSTFIELDS
CURLOPT_POSTFIELDS => $final
may it helps ....
I am trying to post the following data to an endpoint built up on Laravel.
{
"category": "2",
"title": "my text goes here",
"difficulty": 1,
"correct": {
"id": "NULL",
"text": "Correct"
},
"wrong": [
{
"id": "NULL",
"text": ""
},
{
"id": "NULL",
"text": ""
},
{
"id": "NULL",
"text": ""
}
]
}
and I have the following validation rules.
return [
'correct' => 'required|array',
'correct.text' => 'required',
'wrong' => 'required|array|between:1,3'
];
What I am trying to accomplish is the wrong should be and array and it should contain at least one element and should not exceed 3. Now these rules are satisfying, but there is one more case I need to take care and that is the validation of the text in wrong . With the current rules, if I post the above data, it will accept as there is no rule in place for the text in the wrong section. Which rule I need to add to validate that the wrong section at least contains one entry with a not empty text.
tl;dr
If you have very specific needs for a validator rule, you can always create your own.
Create a Custom Validator
The scheme will be: properties_filled:propertyName:minimumOccurence. This rule will check if the field under validation:
Is an array.
Its elements have at least minimumOccurence amounts of non empty (!== '') values among element properties called propertyName.
In your app/Providers/AppServiceProvider.php file's boot method, you can add the custom rule implementation:
public function boot()
{
Validator::extend('properties_filled', function ($attribute, $value, $parameters, $validator) {
$validatedProperty = $parameters[0];
$minimumOccurrence = $parameters[1];
if (is_array($value)) {
$validElementCount = 0;
$valueCount = count($value);
for ($i = 0; $i < $valueCount; ++$i) {
if ($value[$i][$validatedProperty] !== '') {
++$validElementCount;
}
}
} else {
return false;
}
return $validElementCount >= $minimumOccurrence;
});
}
Then you can use it in your validation like this:
return [
'correct' => 'required|array',
'correct.text' => 'required',
'wrong' => 'required|between:1,3|properties_filled:text,1'
];
Testing
Note: I assumed that you parse your JSON data with json_decode's $assoc parameter set to true. If you use an object then change the $value[$i][$validatedProperty] !== '' in the condition to: $value[$i]->{$validatedProperty} !== ''.
Here is my example test:
$data = json_decode('{"category":"2","title":"mytextgoeshere","difficulty":1,"correct":{"id":"NULL","text":"Correct"},"wrong":[{"id":"NULL","text":""},{"id":"NULL","text":""},{"id":"NULL","text":""}]}', true);
$validator = Validator::make($data, [
'correct' => 'required|array',
'correct.text' => 'required',
'wrong' => 'required|between:1,3|properties_filled:text,1'
]);
$validator->fails();
Take advantage of the validation rule in
EDIT: I assume that wrong will have a specific value, therefore pass that value in this way
return [
'correct' => 'required|array',
'correct.text' => 'required',
'wrong' => 'required|array|between:1,3',
'wrong.text' => 'sometimes|min:1|in:somevalue,someothervalue',
];
The sometimes validation makes sure that field is checked only if exists. To check that there will be at least
I'm not sure, but does min suffice to your request? Otherwise you have to write a custom validation rule as someone else suggested
I got the same issue while trying to validate an array on the API side. I made a solution. try this
$validator = Validator::make($request->all(), [
'target_user_ids' => 'required',
'target_user_ids.*' => 'present|exists:users,uuid|distinct',
]);
if ($validator->fails()) {
return response()->json([
'status' => false,
'error' => $validator->errors()->first(),
], 400);
}
If you want to validate input fields in array, you can define your rules like this:
return [
'correct' => 'required|array',
'correct.text' => 'required',
'wrong' => 'required|array|between:1,3',
'wrong.*.text' => 'required|string|min:1',
];
need a little help with League\Fractal, i'm trying to create object to imitate FeatureCollection of GoogleMapApi DataLayer
FeatureCollection
+ type
+ features => [
Feature
{
type,
geometry =>
{
type,
coordinates => [latitude, longitudes]
}
}
]
I've successfully create Transformer for Geometry and Feature, yet having a problem with FeatureCollection because attributes features is an array with element of Feature.
{
"type": "FeatureCollection",
"features": [
[],
[],
]
}
How can i transform the inside of features element correctly?
Well somehow i manage to understand the concept. So basically you need to return the collection with the ObjectTransformer itself, not just the Object.
Just need to add this inside the FeatureCollectionTransformerClass
protected $defaultIncludes =[
'features'
];
public function includeFeatures(FeatureCollection $collection){
return $this->collection($collection->features, new FeatureTransformer());
}
After doing a query, how can I create and echo a formatted JSON like this:
{
"results": [
{
"user_id": "1",
"name": "Apple",
"address": "7538 N LA CHOLLA BLVD",
"city": "Palo Alto",
"state": "CA",
"latlon": [
-111.012654,
32.339807
],
},
{
"user_id": "2",
"name": "Microsoft",
"address": "75 S BWY STE 400",
"city": "Palo Alto",
"state": "CA",
"latlon": [
-73.764497,
41.031858
],
},
],
"meta": {
"page": 1,
"per_page": 10,
"count": 493,
"total_pages": 50
}
}
This is my current query:
public function getAgenciesJson() {
$agencies = DB::table('users')->where('type','a')->orWhere('type','l');
}
Haven't figured out how to output JSON like that, considering I have a "latlon" field like [-111.012654,32.339807], also a "results" tag and a "meta" tag.
Thanks in advance
What you need is something called a transformer (or presenter) to convert your raw model into a format that can be sent to your users.
A very popular package is called Fractal (http://fractal.thephpleague.com/) by Phil Sturgeon. There's a Laravel package, that might make it a bit easier to use, called Larasponse (https://github.com/salebab/larasponse).
Phil actually a blog post about this just the other day - https://philsturgeon.uk/api/2015/05/30/serializing-api-output/ - that goes into why you should always have some kind of transformer between your models and what you send to your users.
There's also a guide about using Larasponse and Fractal that might be of use here - http://laravelista.com/laravel-fractal/.
The gist of it boils down to passing the model through another class that will take the models values and build an array/object in a known/fixed format, e.g. (from Phil's blog post)
return [
'id' => (int) $book->id,
'title' => $book->title,
'year' => (int) $book->yr,
'author' => [
'name' => $book->author_name,
'email' => $book->author_email,
],
'links' => [
[
'rel' => 'self',
'uri' => '/books/'.$book->id,
]
]
];
This way you're not exposing your original field names and if at any point your column names should change you only need to update that in 1 place rather than having to get any user of your JSON to update their site/app. It will also allow you to do string manipulation of your latlon column so that you can split it into 2 different values.
Using a slightly modified example from the Fractal documentation. Say you have a transformer for a User
class UserTransformer extends Fractal\TransformerAbstract
{
public function transform(User $user)
{
return [
'id' => (int) $user->id,
'name' => $user->first_name . ' ' . $user->last_name,
];
}
}
You can then use this class to either transform a single item of a collection
$user = User::find(1);
$resource = new Fractal\Resource\Item($user, new UserTransformer);
// Or transform a collection
// $users = User::all();
// $resource = new Fractal\Resource\Collection($users, new UserTransformer);
// Use a manager to convert the data into an array or json
$json = (new League\Fractal\Manager)->createData($resource)->toJson();
Fractal includes a paginator adapter for Laravel that can be used straight away
$paginator = User::paginate();
$users = $paginator->getCollection();
$resource = new Collection($users, new UserTransformer);
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
The method exists:
->toJson()
REF: http://laravel.com/docs/4.2/eloquent#converting-to-arrays-or-json
Update your getAgenciesJson to :
public function getAgenciesJson() {
return DB::table('users')->where('type','a')->orWhere('type','l')->toJson();
}
Then you could echo by:
<?= SomeModel::getAgenciesJson(); ?>
To modify the column names you can update your select. Here is an example taken from the Laravel Docs:
$users = DB::table('users')->select('name as user_name')->get();
Here would be a more fully realized version of what you are looking for minus the column aliases since you didn't really mention what they were.
public function getAgenciesJson($page, $per_page = 10) {
$output = [
'results' => [],
'meta' => [],
];
// Get Results
$output['results'] = DB::table('users')->where('type','a')->orWhere('type','l')->take($per_page)->skip($per_page * ($page - 1))->get();
// Set Meta
$output['meta'] = [
'page' => $page,
'per_page' => $per_page,
'count' => DB::select('SELECT FOUND_ROWS()'),
'total_pages' => DB::table('users')->count() / $per_page
];
// Return
return json_encode($output);
}
Your original code didn't attempt to get or handle the pagination information but this example covers that in order to provide the meta data you indicated you wanted returned.
Not sure if you wanted Count to be the number of the current result set or a count of all the records on that table. If you don't want the current set you but rather the entire count you can use DB::table('users')->count() though I would assign it to a variable and use that rather than calling it twice in the meta info.
public function getAgenciesJson() {
$agencies = DB::table('users')->where('type','a')->orWhere('type','l')->get();
return response()->tojson($agencies,200);//for response with status code 200
}
You should call get function to get data in array format and response function will format your output to json. Second paramater signifies which status code you have to assign for your response.
I using Phalcon PHP as PHP MVC Framework with MongoDB.
I can find object according with some criteria:
$user = User::findFirst(array(array('username' => $login, 'email'=> $login)));
As you can note, this request will return me the record according logical AND operator between conditions. I need to form request that will return result according with OR operator between conditions.
The problem also is that I'm using MongoDB, so, as I can suppose, I can't write PHQL request manually.
Just a matter of mangling PHP arrays
$user = User::findFirst( array(
'$or' => array(
array( 'username' => $login),
array( 'email' => $login)
)
));
So not only do I show the answer but also how my totals non PHP mind solves this problem:
$result = '{ "$or": [ { "username": "login" }, { "email": "login" } ] }';
echo var_dump( json_decode( $result ) );
$test = array(
'$or' => array(
array( 'username' => 'login'), array( 'email' => 'login')
)
);
echo json_encode( $test ) ."\n"
So in just a few lines we converted and proved. So since you knew the JSON from either the manual page or reading another question on SO, just convert it. And it's one of the reasons I submit the valid JSON in responses here, is so that the logic can be translated into just about any language implementation.
You can pass column names as string in first param:
$user = User::findFirst('username = "'.$login.'" OR email = "'.$login.'"');
$result = '{ "$or": [ { "username": "login" }, { "email": "login" } ] }';
User::findFirst(array(json_decode($query,true)));
$result is the exact json which can be used to trigger queries in mongodb command line
json_decode with 2nd parameter true will output the array style format of JSON