Instantiate an stdClass object from json schema specification in PHP - php

I have a set of JSON requests that I must send to a RESTFul API in order to get some response objects, you know, the usual thing for a webapp, however these API request objects are properly documented with a json schema specification for each, so I would like to load those schema files and create stdClass object instances based on that info automagically.
Is there some way to do this with a library or something in PHP? (don't want to reinvent the wheel)
Thanks!
Edit: Have a look at this schema file which contains an example of what I want to load and build object instances from.
Disclaimer: I do know json_encode / json_decode which is not what I'm looking for. Using that I'd need to traverse through the returned schema object and then create another object/array based on the schema read, which is not what I want.

I don't think there's a built-in way of doing this, but it should be relatively trivial to implement:
function createObj( $json ) {
$obj_schema = json_decode($json, true);
$new_obj = new StdClass;
foreach($obj_schema['properties'] as $property) {
$new_obj->{$property} = null;
}
return $new_obj;
}

Related

php create several objects within object

I am trying to make a soap request and it needs to have this structure
$requestBody=new sendDataExtraccionRequest(new sendDataExtraccionSubterranea("18-09-2020","00:02:01",1234567891,12345678.12,12345678.12),
new sendDataExtraccionSubterranea("18-09-2020","00:03:01",1234567891,12345678.12,12345678.12));
thought that by creating an array with each object and then cast it should do, but getting an error on the soap call that the date field is missing
$array_datos[] = new sendDataExtraccionSubterranea("03-02-2021","00:02:01",1234567891,12345678.12,12345678.12);
$array_datos[] = new sendDataExtraccionSubterranea("03-02-2021","00:03:01",1234567891,12345678.12,12345678.12);
$requestBody=new sendDataExtraccionRequest( (object)$array_datos );
Also tried a solution that involved json encoding and decoding the array, but same error
Any hint on how to achieve it?
Thanks
Use Spread Operator like this
$requestBody=new sendDataExtraccionRequest(...$array_datos);

Create an array of objects and then fetch object without losing their class

I'm trying to do some experiments with arrays and objects to improve my PHP programming basics.
What I would like to do is to save a collection of objects instantiated by one of my classes in a text file to be able to fetch them later.
My current implementation is to save the objects in an array, encode the array and save it to a JSON file.
However, the problem that arises is that when I then go to extract the objects these are no longer objects deriving from my class but are transformed into stdClass objects.
Here is the method I use to save objects to the file:
public function store(string $titolo, string $nomeAutore, string $titoloToDoList): void
{
FileChecker::FindOrBuild('Data/Tasks.json', "[]");
$newTask = new Task($titolo, $nomeAutore, $titoloToDoList);
$file = file_get_contents('Data/Tasks.json');
$decodedFile = json_decode($file);
array_push($decodedFile, $newTask->toArray());
file_put_contents('Data/Tasks.json', json_encode($decodedFile));
FileChecker::FindOrBuild('log/log.txt', "Logs: \n");
Logger::logTaskStore($nomeAutore, $titoloToDoList);
}
and then I extract from the file with a simple json_decode ()
Can anyone suggest some alternative method to save objects in a text file without losing the class?
edit:
forgot to put the toArray() code which is simply
public function toArray(): array
{
return get_object_vars($this);
}
There are as many file formats as there are people who need to store something slightly different in a file. It's up to you to figure out which one makes sense for your application.
JSON is a file format designed to be very simple and flexible, and portable between lots of different languages. It has no concept of "class" or "custom type", and its "object" type is just a list of key-value pairs. (Have a look at the file your current code creates, and you'll see for yourself.)
You can build a file format "on top of" JSON: that is, rather than storing your objects directly, you first build a custom structure with a way of recording the class name, perhaps as a special key on each object called "__class". Then to decode, you first decode the JSON, then loop through creating objects based on the name you recorded.
You mentioned in comments PHP's built-in serialize method. That can be a good choice when you want to store full PHP data for internal use within a program, and will happily store your array of objects without extra code.
In both cases, be aware of the security implications if anyone can edit the serialized data and specify names of classes you don't want them to create. The unserialize function has an option to list the expected class names, to avoid this, but may have other security problems because of its flexibility.

How do I use DTOs to consume a REST API in PHP?

I have an API to consume for a service that provides finance quotations on used cars. My app is written in PHP and I have Guzzle 5 added via Composer.
I have used other APIs previously that have take XML or just an Array of POST parameters to send, but this one is more complex.
This API uses DTO objects and the documentation says this:
relies heavily on DTOs to carry data between client and server. The following
sections detail the DTOs. Each web service will serialise and transfer them in their own
formats/methods. It is the responsibility of the client application to correctly construct requests and
parse responses. It is suggested that object serialization and deserialization be used for easier usage.
So I have no idea how to achieve this with Guzzle. Some of the enumeration types are things such as "RequestAssetMotorVehicle". Would you use StdClass or Arrays doing this in PHP? Or classes? How would I serialise it?
Guzzle Docs
Without the API's documentation this is difficult to express. But I'll try. We'll use a generic JSON based REST API
DTO standards are usually per company and sometimes per application. In short: A DTO is a serialized object.
Let's say this is a POST request ( we're creating a new user)
{
'name':'john',
'foo':'bar',
'site':'stackoverflow.com'
}
That JSON is a DTO. Now let's do a GET
{
'error':false,
'results':2,
'data': [{'name':'john','foo':'bar','site':'stackoverflow.com'},
{'name':'mark','foo':'bar','site':'notstackoverflow.com'}]
}
the array of 'data' is an array of DTO.
So what the dox are telling you is that you need to familiarize your application with the API by creating a layer for that data to pass through to be formed into objects on your side and the same layer should take an object and turn it into a DTO. In some cases you can just handle the responses from API's with simple code, however in a situation were the GET request would return more than 10 results you are going to want to parse it with some class. Essentially creating an ORM for DTOs.
As far as guzzle goes: set the body to what ever the results of pushing the data through the layer.
public function createUserWithSomeApi()
{
$g= new \Guzzle\Client();
$response = $g->post('http://api.some.place/v1/users', [
'body' => (new strangeApiDtoParser)->prepare($new_user_data)
]);
return ApiDtoParser::fromDTO($response->getBody());
}
And receive
public function getUsersFromSomeApi()
{
$g= new \Guzzle\Client();
$response = $g->get('http://api.some.place/v1/users', [
'query' => ['foo' => 'bar']
]);
return ApiDtoParser::fromDTO($response->getBody());
}
Now your parser:
class ApiDtoParser
{
public static function fromDto($raw)
{
$returnArray=[];
$decoded =json_decode($data,true);
foreach($decoded as $one){
$obj = new DtoObj;
foreach ($one as $key => $value) {
$meth = "set". ucfirst(strtolower($key));
$obj->{$meth}($var);
}
$returnArray[]=$obj;
}
return $returnArray;
}
}
Judging by the context of you excerpt, You will need to create a request based parser though

PHP MVC - Convert JSON to Model data

So essentially I find myself writing a bunch of boiler plate code that takes info from a JSON encoded string and puts that data into the models used in my MVC web app. Is there an accepted method of doing this? Should every model have an associative array to model object converter? Should there be a utility class I write to do this? Basically, I am just trying to remove that code from my controllers to slim them down and I am new to PHP MVC. I am using Kohana 3.2 if that is of any relevance to the question.
EDIT:
I was asked to clarify. I receive data in string format that is JSON encoded (from a web service of my own writing - Java /w Jersey). So essentially, the models in my web app are not pulling their information from a database, but rather from a web service. Since the web service returns everything in JSON format, I find myself writing code that deals with that issue. The other way around, I can tell the GSON google code to convert JSON to a particular Java object. There does not seem to be a one liner way to do this in PHP. I am not talking about the stdClass object, but a model.
Your model must implement simple interface with method fromArray($array)
public function fromArray(array $array)
{
foreach($array as $property => $value) {
if(property_exists($this, $property) {
$this->$property = $value;
}
}
}
Kohana's models (ORM calss) only works with databse records. If you'd like to use Kohana you'll have to write new module based in ORM module. This module can have the actually do same things with model (load, save) but it's gona work with you input data.

PHP Web Service - Same call: Multiple records = array, 1 record=single object - How to work around?

I'm consuming a web service in PHP. If the service returns 2 or more records the object comes back as an array. However, if I call the same service that returns 1 record, the object is not an array. This makes for some messy logic having to watch for both cases when one would think PHP could be smart enough to handle this appropriately and always return an array of 1 element.
So my question is - is there a way to force the return object to always be an array? Some property in the call or something?
EDIT
I'm using PHP's soapclient library. The service is an in-house one that returns an array of a custom class.
you could try the following:
$client = new SoapClient("http://host/services/some.wsdl",
array('feature' => SOAP_SINGLE_ELEMENT_ARRAYS));
This should make php behave the way you want.
Also you might find this dotvoid article interesting.
HTH

Categories