PHP code example of romanko / object-graph

1. Go to this page and download the library: Download romanko/object-graph library. Choose the download type require.

2. Extract the ZIP file and open the index.php.

3. Add this code to the index.php.
    
        
<?php
require_once('vendor/autoload.php');

/* Start to develop here. Best regards https://php-download.com/ */

    

romanko / object-graph example snippets



/**
 * @property string   $firstName
 * @property string   $lastName
 * @property string   $fullName
 * @property DateTime $dateOfBirth
 * @property string   $email
 * @property string   $schema      Payload version
 */
class User extends GraphNode
{
    const SCHEMA_V1 = 'v1';
    const SCHEMA_V2 = 'v2';
}



class UserSchemaV1 extends Schema
{
    public function getGraphNodeClassName(): string
    {
        return User::class; // the Resolver must use User model class
    }

    public function isStrict(): bool
    {
        return true; // this is a strict schema
    }

    protected function build(SchemaBuilder $schema)
    {

        /**
         * Use $schema to define fields: addField() returns an instance of the FieldBulder class
         */

        $schema->addField('firstName')->withResolver(function (stdClass $data) {
            if (empty($data->userName)) {
                return null;
            }

            $name = preg_split('/\s+/', $data->userName, 2);

            return $name[0];
        });

        /**
         * Field resolver function is the most powerful way to extract data from the data source.
         */

        $schema->addField('lastName')->withResolver(function (stdClass $data) {
            if (empty($data->userName)) {
                return null;
            }

            $name = preg_split('/\s+/', $data->userName, 2);

            return (sizeof($name) === 2 ? $name[1] : null);
        });

        /**
         * Defining a field aliase allows to avoid using resolver. This code below tells that, 
         * there is a Model property "fullName", which must receive data from the source object 
         * field named "userName".
         */

        $schema->addField('fullName')->asAliasOf('userName');

        /**
         * Additionally, a type of resulting value can be specified on a field
         */

        $schema->addField('dateOfBirth')->asAliasOf('dob')->asScalarValue(ScalarType::DATE_TIME);
        $schema->addField('email')->asAliasOf('emailAddress');

        /**
         * You can specify a default value for an existing field or define a "virtual" 
         * field with the default value.
         */

        $schema->addField('schema')->withDefaultValue(User::SCHEMA_V1);
    }
}


class UserSchemaV2 extends Schema
{
    public function getGraphNodeClassName(): string
    {
        return User::class;  // the Resolver use User model class
    }

    public function isStrict(): bool
    {
        return true; // this is a strict schema
    }

    protected function build(SchemaBuilder $schema)
    {

        /**
         * If source object field name and Model property name match and you are happy with 
         * the type of the source value, this is what you only need to register a field.
         */

        $schema->addField('firstName');
        $schema->addField('lastName');

        $schema->addField('fullName')->withResolver(function (stdClass $data) {
            if (empty($data->firstName) || empty($data->lastName)) {
                return null;
            }

            return sprintf('%s %s', $data->firstName, $data->lastName);
        });

        $schema->addField('dateOfBirth')->asScalarValue(ScalarType::DATE_TIME);
        $schema->addField('email');
        $schema->addField('schema')->withDefaultValue(User::SCHEMA_V2);
    }
}

$resolver = new Resolver();

$model1 = $resolver->resolveObject($userPayloadV1, UserSchemaV1::class);
$model2 = $resolver->resolveObject($userPayloadV2, UserSchemaV2::class);

echo $model1->firstName; // outputs "Arnold"
echo $model2->firstName; // outputs "Arnold"


class UserResolver extends Resolver
{

    /**
     * Let's override Resolver::resolveObject() in our own resolver and
     * make it inspect the raw source object to decide which schema version 
     * to use
     */
  
    public function resolveObject(
        stdClass $data = null,
        string $schemaClassName = null,
        Context $context = null
    ): GraphNode {
        if (empty($data)) {
            return null;
        }

        switch (true) {
            case (
                  isset($data->fullName) || 
                  isset($data->dob) || 
                  isset($data->emailAddress)
            ): // it is definitely a v1 User payload
                $schemaClassName = UserSchemaV1::class; 
                break;

            case (
                (isset($data->firstName) && isset($data->lastName)) ||
                isset($data->emailName) ||
                isset($data->dateOfBirth)
            ): // it is clearly a v2 User payload
                $schemaClassName = UserSchemaV2::class; 
                break;

            default:
                throw new ObjectGraphException('Unable to detect schema from the user data object');
        }

        /**
         * Call parent::resolveObject() with a Schema class we have just detected
         */

        return parent::resolveObject($data, $schemaClassName, $context);
    }
}

$resolver = new Resolver();
$model    = $resolver->resolveObject($anyUserPayload);

echo $model->firstName; // Woo Hoo!! It still outputs "Arnold"!



$context = new Context();
$context['locale'] = 'en-au';

$og = new ObjectGraph($context);
$model = $og->resolveObject($json);

echo $model->sayHi;


// defining new field and its resolver in Schema
$schema
  ->addField("sayHi")
  ->withResolver(function(stdClass $data, Context $context) {
    $locale = $context['locale']; // get locale from the Context
    $fallbackLocale = 'en-us';

    return (isset($data->greetings->$locale) ? 
      $data->greetings->$locale : 
      $data->greetings->$fallbackLocale);
  });