0

Im a fan of the jackson mapper in Java, and I'm a bit lost without it in php. I would like an equivalent.

So far the closest I have come across is this, however, it requires the fields to be declared as public, and I dont want to do that:

https://github.com/netresearch/jsonmapper

I want something that does everything that that does, with this sort of code:

<?php
class Contact
{
    /**
     * Full name
     * @var string
     */
    public $name; //<- I want this to be private

    /**
     * @var Address //<- and this
     */
    public $address;
}

class Address
{
    public $street;<- and this
    public $city;<- and this

    public function getGeoCoords()
    {
        //do something with the $street and $city
    }
}

$json = json_decode(file_get_contents('http://example.org/bigbang.json'));
$mapper = new JsonMapper();
$contact = $mapper->map($json, new Contact());

Json from file_get_contents:

{
    'name':'Sheldon Cooper',
    'address': {
        'street': '2311 N. Los Robles Avenue',
        'city': 'Pasadena'
     }
}

So I dont want to be writing individual constructors, or anything individual at all.

Im sure there would be something that does this out of the box using reflection?

3
  • Give us a quick idea of what Jackson or "that" does exactly...? Commented Nov 10, 2015 at 15:34
  • I forgot the json file. It maps that to the php classes. Commented Nov 10, 2015 at 15:37
  • Jackson will throw the json into java classes like above with private instance variables via reflection with no fuss. Commented Nov 10, 2015 at 15:39

3 Answers 3

2

This can be achieved very easily and nicely using Closures. There is even no need to create setter functions.

<?php

    class A {
        private $b;
        public $c;

        function d() {

        }
    }

    $data = [
        'b' => 'b-value',
        'c' => 'c-value',
        'd' => 'function',
    ];

    class JsonMapper {
        public function map( $data, $context ) {
            $json_mapper = function() use ( $data ) {
                foreach ($data as $key => $value) {
                    if ( property_exists( $this, $key ) ) {
                        $this->{$key} = $value;
                    }
                }
            };

            $json_mapper = $json_mapper->bindTo( $context, $context );
            $json_mapper();

            return $context;
        }
    }

    $mapper = new JsonMapper();
    $a = $mapper->map( $data, new A );

    print_r($a);
Sign up to request clarification or add additional context in comments.

Comments

2

You can provide a setter method for protected and private variables:

public function setName($name)
{
    $this->name = $name;
}

JsonMapper will automatically use it.


Since version 1.1.0 JsonMapper supports mapping private and protected properties.

Comments

0

Sorry, I don't have enough 'reputation' so can't add a comment.

I've only been using Java for a few month, but my understanding is that your classes in Java will all have getters and settings, which is how Jackson is able to set the value of a private property.

To do the same in PHP, I suspect you would need to make your properties private, and create getter and setter methods...

public function setName($name) {
    $this->name = name;
}

Then within your Mapper, use reflection to call the setter.

The way I would do this would be to look at the keys you have in the JSON, and try to put together a method name.

For example, if there's a key in the JSON labelled 'name'...

$className = "Contact";
$object = json_decode($jsonResponse);

$classObject = new $className();

foreach ($object as $key => $value) {
    $methodName = "set" . ucfirst($key);

    if (method_exists($classObject, $methodName)) {
        $classObject->$methodName($value);
    }
}

The above may not be exactly right, but I hope it gives you an idea.

To expand on the above, I've put together the following example which seems to do what you require?

class Contact {

    private $name;
    private $telephone;

    public function setName($name) {
        $this->name = $name;
    }

    public function setTelephone($telephone) {
        $this->telephone = $telephone;
    }

    public function getName() {
        return $this->name;
    }

    public function getTelephone() {
        return $this->telephone;
    }

}

class Mapper {

    private $jsonObject;

    public function map($jsonString, $object) {
        $this->jsonObject = json_decode($jsonString);

        if (count($this->jsonObject) > 0) {
            foreach ($this->jsonObject as $key => $value) {
                $methodName = "set" . ucfirst($key);

                if (method_exists($object, $methodName)) {
                    $object->$methodName($value);
                }
            }
        }

        return $object;
    }

}

$myContact = new stdClass();
$myContact->name = "John Doe";
$myContact->telephone = "0123 123 1234";

$jsonString = json_encode($myContact);

$mapper = new Mapper();
$contact = $mapper->map($jsonString, new Contact());

echo "Name: " . $contact->getName() . "<br>";
echo "Telephone: " . $contact->getTelephone();

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.