Создание дерева классов php из объекта json

РЕДАКТИРОВАТЬ

Хорошо, кажется, я действительно плохо описываю свою проблему. я нашел этот генератор в Интернете, и то, что я ищу, это то же самое, но для php-кода. любая идея ?


ОРИГИНАЛЬНЫЙ ВОПРОС

Я готов построить много классов php из представления json (сопоставление API с объектом), и для этого я хотел бы преобразовать это:

{
"success": true,
"domains": [
{
"id": "13",
"manual": "0",
"name": "silo3.mobi",
"lastname": "Doe",
"firstname": "John",
"cid": "1",
"period": "1",
"recurring_amount": "9.95",
"currency_id": "0",
"module": "namesilo",
"next_due": "2012-12-12",
"expires": "2012-12-12",
"status": "Active",
"type": "Register",
"date_created": "2011-12-12",
"autorenew": "1",
"reglock": "1",
"idprotection": "1"},
{
"id": "11",
"manual": "0",
"name": "netearthorg.org",
"lastname": "Doe",
"firstname": "John",
"cid": "1",
"period": "1",
"recurring_amount": "9.95",
"currency_id": "0",
"module": "NetEarthOne",
"next_due": "2012-11-22",
"expires": "2012-11-22",
"status": "Active",
"type": "Register",
"date_created": "2011-11-22",
"autorenew": "1",
"reglock": "1",
"idprotection": "0"},
{
"id": "10",
"manual": "0",
"name": "hbappreseller.co.uk",
"lastname": "Blue",
"firstname": "Mike",
"cid": "6",
"period": "2",
"recurring_amount": "9.95",
"currency_id": "0",
"module": "NetEarthOne",
"next_due": "2012-11-22",
"expires": "0000-00-00",
"status": "Pending",
"type": "Register",
"date_created": "0000-00-00",
"autorenew": "1",
"reglock": "0",
"idprotection": "0"}
],
"call": "getDomains",
"server_time": 1323793581
}

к объекту со свойством bool: success, массиву объекта «домен» и так далее.

Это не так сложно сделать, я мог бы сам это развить, но мне интересно, есть ли какие-нибудь php-библиотеки, которые позаботятся об этом, не нашли ничего

РЕДАКТИРОВАТЬ

Хорошо, я не очень хорошо себя объяснил, наверное, я хотел бы создать файл класса php, с зависимостями от других классов и так далее, чтобы я мог соответствовать структуре json.

Например, данный json должен генерировать следующее:

class Domain {
protected $id;
protected $manual;
protected $name;
protected $lastname;
protected $firstname;
protected $cid;
protected $period;
protected $recurring_amount;
// and so on
}

Цель состоит в том, чтобы обслуживать WSDL со сложными объектами и не допускать эволюции сигнатуры wsdl, если в исходный API были внесены какие-либо изменения (пользовательские классы не изменятся динамически, только при желании, поэтому WSDL останется прежним)

API генерирует сотни объектов json, некоторые из которых имеют общие свойства, поэтому цель этого состоит в том, чтобы иметь глобальный способ обработки всех строк json и создания или получения построенных объектов, например, два json могут иметь свойство «domains», поэтому в первый раз я хочу создать класс с именем Domain (если свойство = массив, то создать файл с именем свойства -S и заполнить атрибутами, а затем сохранить в файл для дальнейшего использования)

2

Решение

Допустим, ваш JSON-объект хранится в $jsonтогда вы можете создать класс на лету, как это —

$data = json_decode($json, true);

$class = new Domain();
foreach ($data AS $key => $value) $class->{$key} = $value;

Если вы хотите более общий способ, скажем, вы хотите изменить имя класса на лету —

$data = json_decode($json, true);

$className = "Domain"; // Or assign it to something else like pick from DB, from JSON from anywhere.
$class = new {$className}();
foreach ($data AS $key => $value) $class->{$key} = $value;
2

Другие решения

Хорошо, в конце концов я не нашел ничего, что могло бы сделать инструмент json2csharp, поэтому я разработал свой:

namespace Hostbill\Api\Generator;use Zend\Code\Generator\ClassGenerator;
use Zend\Code\Generator\PropertyValueGenerator;
use Zend\Code\Reflection\ClassReflection;
use Zend\Json\Json;
use Zend\Json\Exception\RuntimeException as JsonRuntimeException;

class DataGenerator extends AbstractGenerator
{
const DATA_NAMESPACE = 'Hostbill\Api\Data';
const RESPONSE_SUFFIX = 'Response';
const DATA_ABSTRACT_CLASS = 'AbstractData';

/**
* @var ClassGenerator[]
*/
protected $classes = array();

/**
* @var ClassGenerator
*/
protected $responseClass;

/**
* Build classes from a source json string
* @param string $json
*/
public function fromSource($json)
{
try {
$data = Json::decode($json, Json::TYPE_ARRAY);
} catch (JsonRuntimeException $e) {
$this->err(sprintf('Could not generate classes for given Json, err:"%s"', $e->getMessage()));
return;
}

$this->parse($data);

// write classes files
$this->write($this->responseClass, sprintf('%s/../Data/', __DIR__));

foreach ($this->classes as $class) {
if (self::RESPONSE_SUFFIX === substr($class->getName(), -strlen(self::RESPONSE_SUFFIX))) {
$this->write($class, sprintf('%s/../Data/Response/', __DIR__));
} else {
$this->write($class, sprintf('%s/../Data/', __DIR__));
}
}
}

/**
* Parse json decoded object and generate corresponding classes
* @param array $data associative array retrieved from json_decode
* @return DataGenerator
*/
public function parse($data)
{
$responseClassNamespace = sprintf('%s\%s', self::DATA_NAMESPACE, self::RESPONSE_SUFFIX);

// get "call" property and build Response class name on it: getClientDetails => ClientDetailResponse
$parts = preg_split('/(?=[A-Z])/', $data['call'], -1, PREG_SPLIT_NO_EMPTY);
array_shift($parts); // remove verb
$parts[] = $this->inflector()->singularize(array_pop($parts));
$parts[] = self::RESPONSE_SUFFIX;
$baseResponseClassName = sprintf('%s\%s', self::DATA_NAMESPACE, self::RESPONSE_SUFFIX);
$responseClass = new ClassGenerator(
implode('', $parts),
$responseClassNamespace,
null,
self::RESPONSE_SUFFIX
);
$responseClass->addUse($baseResponseClassName);
$this->addClass($responseClass);

if (!class_exists($baseResponseClassName)) {
$baseResponseClassGenerated = true;
$baseResponseClass = new ClassGenerator(
self::RESPONSE_SUFFIX,
self::DATA_NAMESPACE,
ClassGenerator::FLAG_ABSTRACT
);
} else {
$baseResponseClassGenerated = false;
$baseResponseClass = ClassGenerator::fromReflection(new ClassReflection($baseResponseClassName));
}
$this->responseClass = $baseResponseClass;

foreach ($data as $key => $value) {
$key = $this->inflector()->pascalize($key);
if (is_scalar($value)) {
// thoses properties belongs to the response class
// if we just have generated the "base" response class (Response.php)
// store properties there (there are only 3 basic properties: success, call, serverTime)
// otherwise store them in the child response class, but avoid any overriding of the
// 3 properties which are stored in base Response class
if ($baseResponseClassGenerated) {
$responseClassToUpdate = $baseResponseClass;
} else {
$responseClassToUpdate = $responseClass;
}
// update base response class
if (!$responseClassToUpdate->hasProperty($key) && !$baseResponseClass->hasProperty($key)) {
$responseClassToUpdate->addProperty($key);
}
} else {
// object
if ($this->isArrayAssociative($value)) {
if (!$responseClass->hasProperty($key)) {
$responseClass->addProperty($key);
}
$this->parseObject($key, $value);

// array
} else {
if (!$responseClass->hasProperty($key)) {
$responseClass->addProperty($key, new PropertyValueGenerator(array(), PropertyValueGenerator::TYPE_ARRAY));
}

// if array is simple array, do nothing
if (!is_scalar(reset($value))) {
$this->parseArrayOfObjects($key, $value);
}
}
}
}
return $this;
}

/**
* Parse ordered array and create class object
* @param string $name key name
* @param array $data
* @return DataGenerator
*/
public function parseArrayOfObjects($name, $data)
{
$class = $this->getOrCreateClass($this->inflector()->singularize($name));

foreach ($data as $object) {
foreach ($object as $key => $value) {
if (!$class->hasProperty($key)) {
$class->addProperty($key);
}
}
}

return $this;
}

/**
* Parse associative array and create class object
* @param string $name key name
* @param array $data
* @return DataGenerator
*/
public function parseObject($name, $data)
{
$class = $this->getOrCreateClass($this->inflector()->singularize($name));

foreach ($data as $key => $value) {
if (!$class->hasProperty($key)) {
$class->addProperty($key);
}
}

return $this;
}

/**
* Add class to current stack
* @param ClassGenerator $class
* @return DataGenerator
*/
protected function addClass(ClassGenerator $class)
{
$this->classes[$this->inflector()->lowerize($class->getName())] = $class;
return $this;
}

/**
* Get class from current stack
* @param string $name
* @return false|ClassGenerator False if not found
*/
protected function getClass($name)
{
$id = $this->inflector()->lowerize($name);
if (!isset($this->classes[$id])) {
return false;
}
return $this->classes[$id];
}

/**
* Try to retrievea class from current stack, create it if not found
* @param string $name
* @return ClassGenerator
*/
protected function getOrCreateClass($name)
{
if (!$class = $this->getClass($name)) {
$class = new ClassGenerator(
$this->inflector()->camelize($name),
self::DATA_NAMESPACE,
null,
self::DATA_ABSTRACT_CLASS
);
$this->addClass($class);
}
return $class;
}

/**
* Check if the given array is associative
* @param array $array
* @return bool
*/
protected function isArrayAssociative($array)
{
return (bool)count(array_filter(array_keys($array), 'is_string'));
}
}

Этот код ориентирован на мои потребности, но его легко адаптировать к любому файлу json, вот результат:

JSON

  {
"success": true,
"client": {
"id": "1",
"email": "jondoe@email.com",
"password": "474bf122c92de249ace867a003cb7196",
"lastlogin": "2011-11-25 04:32:40",
"ip": "213.54.21.3",
"host": "cmt-random.uk",
"status": "Active",
"parent_id": "0",
"firstname": "John",
"lastname": "Doe",
"companyname": "",
"address1": "Address 54",
"address2": "",
"city": "Soullans",
"state": "Birmingham",
"postcode": "B33 8TH",
"country": "GB",
"phonenumber": "357755733",
"datecreated": "2011-09-24",
"notes": "",
"language": "spanish",
"company": "0",
"credit": "0.00",
"taxexempt": "0",
"latefeeoveride": "0",
"cardtype": "Visa",
"cardnum": null,
"expdate": null,
"overideduenotices": "0",
"client_id": "1",
"currency_id": "0",
"countryname": "United Kingdom"},
"call": "getClientDetails",
"server_time": 1323442995

}

СОЗДАННЫЕ ФАЙЛЫ (блоки документов отсутствуют, но будут интегрированы, чтобы WSDL обслуживался правильно)

ClientResponse.php (базовый объект)

namespace Hostbill\Api\Data\Response;

use Hostbill\Api\Data\Response;

class ClientResponse extends Response
{

public $clientId = null;

public $info = array(

);}

Client.php

namespace Hostbill\Api\Data;

class Client extends AbstractData
{

public $id = null;

public $email = null;

public $password = null;

public $lastlogin = null;

public $ip = null;

public $host = null;

public $status = null;

public $parent_id = null;

public $firstname = null;

public $lastname = null;

public $companyname = null;

public $address1 = null;

public $address2 = null;

public $city = null;

public $state = null;

public $postcode = null;

public $country = null;

public $phonenumber = null;

public $datecreated = null;

public $notes = null;

public $language = null;

public $company = null;

public $credit = null;

public $taxexempt = null;

public $latefeeoveride = null;

public $cardtype = null;

public $cardnum = null;

public $expdate = null;

public $overideduenotices = null;

public $client_id = null;

public $currency_id = null;

public $countryname = null;

public $services = null;
}
1

На мой взгляд, вы не должны создавать объекты для общих данных, как это. Вы можете легко сопоставить это с универсальным объектом данных.

Таким образом, ваш фреймворк будет просто стандартным PHP. Подобно :

class JsonObject
{

protected $data = array();

public function __construct($data)
{
$this->data = $data;
}

public function __get($var)
{
if (array_key_exists($var, $this->data)) {
return $this->data[$var];
} else {
throw new Exception($var . ' not found in ' . __CLASS__);
}
}

public function __set($var, $val)
{
if (array_key_exists($var, $this->data)) {
return $this->data[$var];
} else {
throw new Exception($var . ' not found in ' . __CLASS__);
}
}}

class Domain extends JsonObject
{
//some domain specific functionality

}

class getDomainResult
{

public $domains = array();
public $success = false;
public $lastTime = 0;

//some methods to do the calls

public function callback($result)
{
$res = json_decode($result, true);
$this->success = $res['success'];
$this->lastTime = $res['server_time'];
foreach ($res['domains'] as $domain) {
$this->domains[] = new Domain($domain);
}
}
}
0
По вопросам рекламы ammmcru@yandex.ru
Adblock
detector