League\Fractal transform item inside array - php

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());
}

Related

How can I return an array in GraphQL if I don't know how many there are (PHP, rebing/graphql-laravel)

There is a JSON array:
[{
"src":{
"hd":"1.jpeg",
"small":"2.jpeg"
}},
{
"src":{
"hd":"1.jpeg",
"small":"2.jpeg"
}
}]
How do I get the list through GraphQL? I don't know how many elements there are.
I can get a one dimensional array with pictures:
$pictures = new ObjectType(
[
'name' => 'pictures',
'fields' => [
'small' => [
'type' => Type::string(),
],
'hd' => [
'type' => Type::string(),
],
]
]
);
return [
......
'image' => [
'type' => $pictures,
'is_relation' => false,
'resolve' => function ($content) {
return $content->image[0]; // I return one here, but I need a list
},
],
......
But how can I get an array of pictures if I don't know how many there are? Maybe one picture, maybe 10.
Googled for half a day, found information that GraphQL can return only what is hardcoded... Is it so?
It is not necessary to know the number of images.
It seems that you need to define the Type of the field images correctly.
GraphQL know custom types and primitives.
type Image{
name: String!
small: String!
}
Image is a custom type, String is a primitive or basic type.
What you are probabably missing is, that you can have a list of a certain type.
I don't know your GQL framework, but here is an example:
Line 23:
https://github.com/rebing/graphql-laravel/blob/master/example/Query/UsersQuery.php
Look at Type::listOf()
So, what you will need to do:
define an ObjectType for a single Image (your current $images type)
And then have a field images in your schema defined as return type list of image
Then you can resolve with return $content->image instead of return $content->image[0]

the match filter must be an expression in an object with mongo aggregation in PHP

So first here's what I'm trying to do :
I got a datatable with some custom inputs. Users can select skills (php, mysql etc) and the standard text input. Users can select multiple skills. When multiple skills are selected it's supposed to be kind of an AND AND query. So both skills must be available.
The standard text input in datatables would contain information such as the name of a customer, their email or job function.
For example I check PHP and Javascript, in my text search I put Google.
Which would mean I'm looking for a document which has both PHP and Javascript in the tags (Or any of their aliases eg: Javascript => js), and has google in any other field thats listed (Customer, function, sender name, sender email or subject).
But it should also be able to search for documents just matching the skills or only for the text input.
I have been trying to build arrays with all query options and merge those depending on input to the function but so far nothing has been working.
the match filter must be an expression in an object
So below is an example of a document I got in Mongo
{
"_id": {
"$oid": "superfancyID"
},
"parsed": {
"tags": [
"sql",
"php"
],
"customer": "CustomerName",
"function": "functionName",
"mail_properties": {
"senderName": "SenderName",
"senderEmail": "example#example.com",
"subject": "FW: Test email",
}
}
}
Here is some code I got to try and build my query
public function handler(int $skip, int $limit, array $filters, string $filterString = '') {
# $filters are skills
# $filterString is a string of everything else you put in the search field of the datatable
/** #var \MongoDB\Collection $collection */
$collection = $this->emailRepository->getCollection();
/** #var array $regex */
$regex = [];
if(!empty($filterString))
{
$strings = explode(' ', $filterString);
foreach($strings as $item)
{
$regex[] = new Regex($item, 'i');
}
}
#This function basically does the same as above.
#The only change is that this also goes over any aliases for skills. (Javascript => js)
/** #var array $aliasRegex */
$aliasRegex = $this->createAliasRegex($filters);
$skillsFilters = [];
#This is where I attempt to create a part of the query for just the skills.
if(!empty($aliasRegex)) {
$skillsFilters = [
'$and' => [
'$or' => [
['parsed.tags' => [
'$in' => $aliasRegex
]]
]
]
];
}
$stringFilters = [];
#This is where I try and build the rest of the query.
if(!empty($regex)) {
$stringFilters = ['$or' =>
['parsed.function' => [
'$in' => $regex
]],
['parsed.mail_properties.subject' => [
'$in' => $regex
]],
['parsed.customer' => [
'$in' => $regex
]]
];
}
$documents = $collection->aggregate([
[
'$match' => [
array_merge($stringFilters, $aliasFilters)
]
]
,[
'$limit' => $limit,
],[
'$skip' => $skip
]
]);
This is basically all I got, I tried checking my arrays and moving around some parts but nothing has been working for me. I always been getting back the error
the match filter must be an expression in an object

Get form/fieldset element name inside custom validator class in ZF3

I created my custom validator class that implemented ValidatorInterface. How to get element name of the fieldset or form that is validated?
I need this inside the validator class.
I am going to do some validating logic inside the class validator cause I am going to use the context array with all values and distinguish which is the current one.
Nope you can't. But you can use callable filter to re-design your value. I don't know if it's reasonable way to do it. I didn't face such a problem like this. But here's an example
$this->add([
/** other settings **/
"filters" => [
[
"name" => \Zend\Filter\Callable::class,
"options" => ["callback" => function($value){
return "fieldset-x:".$value;
}]
]
],
"validators" => [
[
"name" => \Zend\Validator\Callable::class,
"options" => ["callback" => function($value){
/** algorithm: split via ":". first element is freamwork **/
}]
]
]
])
I used callable filter and validator to do is. You may want to write your own filter/validator.

Override/Update Variable/Array in php file

In my recent project, working on console command where I need to perform/run various action mentioned in json based on the linux standard convention as
what:mv(Move),type:file,dir
what:mkdir(Make Directory)
what:touch(Make File)
what:cp(Copy), type:file,dir
what:echo (Write into File), type:override,append
what:sed (Find and Replace in file)
and param schema would be same almost exact to linux convention.
Current SetUp (Mkdir, touch)
Json Schema (Array)
"actions" => [
[
'what' => "mkdir",
'param' => [
'name' => "cache",
'in' => "bootstrap",
],
],
[
'what' => "touch",
'param' => [
'name' => ".gitignore",
'in' => "bootstrap/cache",
],
]
],
and its iterate through all action and resolve action class per what type (mkdir,touch) like MkdirOperation for mkdir and call handle functions respectively.
<?php
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\Filesystem\Exception\IOExceptionInterface;
class MkdirOperation extends Operation
{
const ATTR_IN = "in";
const ATTR_NAME = "name";
public function handle()
{
$path = $this->_path();
$this->oIO->comment($path);
if ($this->oFileSystem->isAbsolutePath($path)) {
try {
$this->oFileSystem->mkdir($path);
} catch (IOExceptionInterface $e) {
echo "An error occurred while creating your directory at "
.$e->getPath();
}
$this->oIO->info("Directory created at:".$path);
}
}
private function _path()
{
return $this->oConfig->getBaseDir()
.$this->aParam[self::ATTR_IN].DIRECTORY_SEPARATOR
.$this->aParam[self::ATTR_NAME]
.DIRECTORY_SEPARATOR;
}
}
Requirement:
//somefile.php
$path = "/var/www/ins/"
//someotherfile.php
return [
'files' = [
'Path\\To\\NameSpace',
'Path\\To\\NameSpace'
]
];
So, basically I want to update/override my mentioned variable/array according to specific rules, for that purpose, I tried to prepare rules in json schema:
"actions": [
{
"what": "sed",
"in": "path/to/somefile.php",
"find": {
"type": "variable",
"value": "path"
},
"replace": {
"type": "variable",
"value": "__DIR__.'/../vendor/compiled.php';"
}
},{
"what": "put",
"value": "Path\\To\\NameSpace",
"in": "path/to/someotherfile.php",
"find": {
"type": "array",
"at": "files"
}
}
]
The Component I'm using
symfony/console
symfony/finder
Symfony/filesystem
Looking for:
Suggestion to organize rules set schema in such manner to iterate through all actions for update/override variable or push/pull element from array and perform action.
Mechanism to update the value of specific variable and also push/pull element from array/subarray using php.
If still something unclear from my side let me know.
Thanks in advance.

Laravel & PHP: Return special formatted JSON

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.

Categories