13

I'm building a REST API endpint that adds a company to a MySQL database. The client sends a POST request with an attached data package. The data package is a JSON object. Assume the JSON Company Object is formatted to exactly match the Company Class that the API uses.

How do I get the JSON Company Object data into the Company Class? It seems silly to instantiate a Company Object, json_decode() the JSON Object, then call dozens of set() methods.

It seems especially silly, since I'm planning on offering the same models in my client package to build the objects that get passed as JSON to my API, before being decoded, and mapped back into the same objects again.

Am I missing something? I'm constantly running up against things that seem redundant while building my API, but perhaps that's just what has to happen.

T. Brian Jones
  • 13,002
  • 25
  • 78
  • 117
  • possible duplicate of [json\_decode to custom class](http://stackoverflow.com/questions/5397758/json-decode-to-custom-class) – cweiske Oct 08 '13 at 11:52

7 Answers7

16

Why don't you handle is all in the constructor of the Company object so that you pass in the JSON object as the parameter and the constructor handles all of the assignments. That way you don't even need public set methods.

$companyData = $_POST['company'];
//or $companyData = json_decode($_POST['company']);
//or whatever depending on how you are posting

class Company {
    private $companyName;
    //etc...
    function __construct(array $data) {
        foreach($data as $key => $val) {
            if(property_exists(__CLASS__,$key)) {
                $this->$key = $val;
            }
        }
    }
}
Carrie Kendall
  • 11,124
  • 5
  • 61
  • 81
km6zla
  • 4,787
  • 2
  • 29
  • 51
11

We built JsonMapper to map JSON objects onto our own model classes automatically.

It only relies on docblock type information for mapping, which most class properties have anyway.

cweiske
  • 30,033
  • 14
  • 133
  • 194
3

Why don't you just make a method in the Company object that declares the variables for the object (you don't need to write a set method for each variable, just one that'll set all the variables).

//Why not write something like this in the class
function setFromJSON($json){
   $jsonArray = json_decode($json, true);
   foreach($jsonArray as $key=>$value){
      $this->$key = $value;
   }
}
Joseph Szymborski
  • 1,241
  • 2
  • 17
  • 31
  • 3
    The second parameter of json_decode has to be set to true, otherwise you cannot do key/value iteration. I made the edit to your answer. – NobleUplift Dec 03 '13 at 16:09
2

this one might help you.

 class ObjectMapper
    {

        protected string $modelClass='';

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

        protected function mapObject(array $values){
            $object = new $this->modelClass();
            foreach ($values as $key=>$value){
                $mapperFunction = 'set'.$key;
                $object->{$mapperFunction}($value);
            }
            return $object;
        }

    }

0

Don't match the JSON data you get exactly to the data object you want to use. There will be changes to the database and the objects, and you do not want these to affect the interface you created and vice versa.

Sven
  • 69,403
  • 10
  • 107
  • 109
0

I Had the same problem, so I wrote a packagist to solve it, here is the gift for you.
https://packagist.org/packages/stark641/stark-object
https://github.com/stark641/stark-object

  1. you can generate PHP class file from json
./vendor/bin/stark-object-gen --path=/tmp --json='{"foo_bar":{"foo":1.3,"bar":[641,641]}}'

output
Class FooBar saved at: /tmp/FooBar.php
Class BaseClass saved at: /tmp/BaseClass.php
  1. you can map json to php object
class FooBarClass extends StarkObject
{
    /** @var string */
    public $foo;

    /** @var integer */
    public $bar;
}

class DemoClass extends StarkObject
{
    /** @var FooBarClass */
    public $foobar;

    /** @var FooBarClass[] */
    public $foobars;

}

$json = '{"foobar":{"foo":"hello world","bar":64100},"foobars":[{"foo":"hello","bar":641},{"foo":"world","bar":664411}]}';
$demo = (new DemoClass())->fromJson($json);

var_export($demo);

0

I think this can help: https://github.com/ABGEO/json-to-popo I tried it and it works fine!

An example:

We have these php classes

<?php

class Department
{
    /**
     * @var string
     */
    private $title;

    // Getters and Setters here...
}
<?php

class Position
{
    /**
     * @var string
     */
    private $title;

    /**
     * @var Department
     */
    private $department;

    // Getters and Setters here...
}
<?php

class Person
{
    /**
     * @var string
     */
    private $firstName;

    /**
     * @var string
     */
    private $lastName;

    /**
     * @var bool
     */
    private $active;

    /**
     * @var Position
     */
    private $position;

    // Getters and Setters here...
}

Person class is represented by this json:

{
  "firstName": "Temuri",
  "lastName": "Takalandze",
  "active": true,
  "position": {
    "title": "Developer",
    "department": {
      "title": "IT"
    }
  }
}

So, now you only need to do this:

// $jsonContent represents your json string
$resultObject = $composer->composeObject($jsonContent, Person::class);
var_dump($resultObject);

and this is what you get:

//class Person#2 (4) {
//  private $firstName =>
//  string(6) "Temuri"
//  private $lastName =>
//  string(10) "Takalandze"
//  private $active =>
//  bool(true)
//  private $position =>
//  class Position#4 (2) {
//    private $title =>
//    string(9) "Developer"
//    private $department =>
//    class Department#7 (1) {
//      private $title =>
//      string(2) "IT"
//    }
//  }
//}

I tried to implement the library with public class properties but it seems it doesn't work without declared setter and getters.