Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

PHP SAMG Generator

The php.samg generator produces PHP SAMG (Schema Auto-Mapping Generation) v2 mapper classes with 10 static methods for bidirectional property mapping and type casting.

Configuration

[generate] = {
  [php.samg] = {
    output = 'output/php/SAMG/'
    namespace = 'App\\SAMG\\'
    map_from = self
    map_to = api
  }
}

Options

OptionRequiredDescription
outputYesOutput directory for generated .php files
namespaceNoPHP namespace prefix for generated classes
map_fromNoSource mapping context (default: self)
map_toNoTarget mapping context

CLI name: php.samg

vendor/bin/scsc gen php.samg schema.scsc --output=output/samg/

Output Files

One <Model>Map.php file per public model. Each class has 10 static methods organized into three categories: full mapping, partial mapping, and in-place casting.

The 10 Methods

Full Mapping (4 methods)

These methods map all properties, using ?? null for missing keys:

MethodDirectionType Casting
localToInterface(array $array): arrayLocal -> InterfaceYes
localToInterfaceMapOnly(array $array): arrayLocal -> InterfaceNo
interfaceToLocal(array $array): arrayInterface -> LocalYes
interfaceToLocalMapOnly(array $array): arrayInterface -> LocalNo

“MapOnly” variants only transform property keys without casting values. Useful when the data is already correctly typed and you only need name conversion.

Partial Mapping (4 methods)

These methods only map properties that exist in the input array, using array_key_exists guards. Ideal for PATCH-style updates:

MethodDirectionType Casting
localToPartialInterface(array $array): arrayLocal -> InterfaceYes
localToPartialInterfaceMapOnly(array $array): arrayLocal -> InterfaceNo
interfaceToPartialLocal(array $array): arrayInterface -> LocalYes
interfaceToPartialLocalMapOnly(array $array): arrayInterface -> LocalNo

In-Place Casting (2 methods)

These methods cast property values in-place by reference, without creating a new array or changing property keys:

MethodContext
castLocal(array &$array): voidCast values using local keys
castInterface(array &$array): voidCast values using interface keys

Example

Given this schema:

User {
  id: uint64
  name: string
}

UserMap.php:

<?php

namespace IntegrationEx\SAMG;

class UserMap
{
    /**
     * @param array<mixed> $array
     * @return array<mixed>
     */
    public static function localToInterface(array $array): array
    {
        return [
            'id' => (string) ($array['id'] ?? null),
            'name' => (string) ($array['name'] ?? null),
        ];
    }

    /**
     * @param array<mixed> $array
     * @return array<mixed>
     */
    public static function localToInterfaceMapOnly(array $array): array
    {
        return [
            'id' => $array['id'] ?? null,
            'name' => $array['name'] ?? null,
        ];
    }

    /**
     * @param array<mixed> $array
     * @return array<mixed>
     */
    public static function interfaceToLocal(array $array): array
    {
        return [
            'id' => (string) ($array['id'] ?? null),
            'name' => (string) ($array['name'] ?? null),
        ];
    }

    /**
     * @param array<mixed> $array
     * @return array<mixed>
     */
    public static function interfaceToLocalMapOnly(array $array): array
    {
        return [
            'id' => $array['id'] ?? null,
            'name' => $array['name'] ?? null,
        ];
    }

    /**
     * @param array<mixed> $array
     * @return array<mixed>
     */
    public static function localToPartialInterface(array $array): array
    {
        $buffer = [];
        if (array_key_exists('id', $array)) {
            $buffer['id'] = (string) ($array['id'] ?? null);
        }
        if (array_key_exists('name', $array)) {
            $buffer['name'] = (string) ($array['name'] ?? null);
        }
        return $buffer;
    }

    /**
     * @param array<mixed> $array
     * @return array<mixed>
     */
    public static function localToPartialInterfaceMapOnly(array $array): array
    {
        $buffer = [];
        if (array_key_exists('id', $array)) {
            $buffer['id'] = $array['id'];
        }
        if (array_key_exists('name', $array)) {
            $buffer['name'] = $array['name'];
        }
        return $buffer;
    }

    /**
     * @param array<mixed> $array
     * @return array<mixed>
     */
    public static function interfaceToPartialLocal(array $array): array
    {
        $buffer = [];
        if (array_key_exists('id', $array)) {
            $buffer['id'] = (string) ($array['id'] ?? null);
        }
        if (array_key_exists('name', $array)) {
            $buffer['name'] = (string) ($array['name'] ?? null);
        }
        return $buffer;
    }

    /**
     * @param array<mixed> $array
     * @return array<mixed>
     */
    public static function interfaceToPartialLocalMapOnly(array $array): array
    {
        $buffer = [];
        if (array_key_exists('id', $array)) {
            $buffer['id'] = $array['id'];
        }
        if (array_key_exists('name', $array)) {
            $buffer['name'] = $array['name'];
        }
        return $buffer;
    }

    /**
     * @param array<mixed> $array
     */
    public static function castLocal(array &$array): void
    {
        $array['id'] = (string) ($array['id'] ?? null);
        $array['name'] = (string) ($array['name'] ?? null);
    }

    /**
     * @param array<mixed> $array
     */
    public static function castInterface(array &$array): void
    {
        $array['id'] = (string) ($array['id'] ?? null);
        $array['name'] = (string) ($array['name'] ?? null);
    }
}

When to Use Which Method

Use CaseMethod
API response -> local storageinterfaceToLocal
Local data -> API requestlocalToInterface
PATCH update (only changed fields)localToPartialInterface / interfaceToPartialLocal
Key rename without casting (pre-casted data)*MapOnly variants
Normalize types on existing arraycastLocal / castInterface