swaggest / php-json-schema

High definition PHP structures with JSON-schema based validation
MIT License
438 stars 50 forks source link

Additional properties not allowed when using addPropertyMapping #63

Closed gigi closed 5 years ago

gigi commented 5 years ago

Hi! Im trying to implement strict schema using additionalProperties: false option and validate it via generated php class. It seems there is an issue for properties added with addPropertyMapping

Test schema:

{
  "$id": "https://example.com/person.schema.json",
  "$schema": "http://json-schema.org/draft-07/schema#",
  "title": "User",
  "type": "object",
  "additionalProperties": false,
  "required": [
    "id",
    "first_name",
    "last_name",
    "age"
  ],
  "properties": {
    "id": {
      "type": "integer",
      "description": "The person's ID."
    },
    "first_name": {
      "type": "string",
      "description": "The person's first name."
    },
    "last_name": {
      "type": "string",
      "description": "The person's last name."
    },
    "age": {
      "description": "Age in years which must be equal to or greater than zero.",
      "type": "integer",
      "minimum": 0
    }
  }
}

Generated class:

<?php
/**
 * @file ATTENTION!!! The code below was carefully crafted by a mean machine.
 * Please consider to NOT put any emotional human-generated modifications as the splendid AI will throw them away with no mercy.
 */

namespace MyNamespace\Model\V1;

use Swaggest\JsonSchema\Constraint\Properties;
use Swaggest\JsonSchema\Schema;
use Swaggest\JsonSchema\Structure\ClassStructure;

/**
 * User
 */
class User extends ClassStructure
{
    /** @var int The person's ID. */
    public $id;

    /** @var string The person's first name. */
    public $firstName;

    /** @var string The person's last name. */
    public $lastName;

    /** @var int Age in years which must be equal to or greater than zero. */
    public $age;

    /**
     * @param Properties|static $properties
     * @param Schema $ownerSchema
     */
    public static function setUpProperties($properties, Schema $ownerSchema)
    {
        $properties->id = Schema::integer();
        $properties->id->description = "The person's ID.";
        $properties->firstName = Schema::string();
        $properties->firstName->description = "The person's first name.";
        $ownerSchema->addPropertyMapping('first_name', self::names()->firstName);
        $properties->lastName = Schema::string();
        $properties->lastName->description = "The person's last name.";
        $ownerSchema->addPropertyMapping('last_name', self::names()->lastName);
        $properties->age = Schema::integer();
        $properties->age->description = "Age in years which must be equal to or greater than zero.";
        $properties->age->minimum = 0;
        $ownerSchema->type = 'object';
        $ownerSchema->additionalProperties = false;
        $ownerSchema->schema = "http://json-schema.org/draft-07/schema#";
        $ownerSchema->title = "User";
        $ownerSchema->required = array(
            0 => 'id',
            1 => 'first_name',
            2 => 'last_name',
            3 => 'age',
        );
    }

    /**
     * @return int
     * @codeCoverageIgnoreStart
     */
    public function getId()
    {
        return $this->id;
    }
    /** @codeCoverageIgnoreEnd */

    /**
     * @param int $id The person's ID.
     * @return $this
     * @codeCoverageIgnoreStart
     */
    public function setId($id)
    {
        $this->id = $id;
        return $this;
    }
    /** @codeCoverageIgnoreEnd */

    /**
     * @return string
     * @codeCoverageIgnoreStart
     */
    public function getFirstName()
    {
        return $this->firstName;
    }
    /** @codeCoverageIgnoreEnd */

    /**
     * @param string $firstName The person's first name.
     * @return $this
     * @codeCoverageIgnoreStart
     */
    public function setFirstName($firstName)
    {
        $this->firstName = $firstName;
        return $this;
    }
    /** @codeCoverageIgnoreEnd */

    /**
     * @return string
     * @codeCoverageIgnoreStart
     */
    public function getLastName()
    {
        return $this->lastName;
    }
    /** @codeCoverageIgnoreEnd */

    /**
     * @param string $lastName The person's last name.
     * @return $this
     * @codeCoverageIgnoreStart
     */
    public function setLastName($lastName)
    {
        $this->lastName = $lastName;
        return $this;
    }
    /** @codeCoverageIgnoreEnd */

    /**
     * @return int
     * @codeCoverageIgnoreStart
     */
    public function getAge()
    {
        return $this->age;
    }
    /** @codeCoverageIgnoreEnd */

    /**
     * @param int $age Age in years which must be equal to or greater than zero.
     * @return $this
     * @codeCoverageIgnoreStart
     */
    public function setAge($age)
    {
        $this->age = $age;
        return $this;
    }
    /** @codeCoverageIgnoreEnd */
}

Usage

        $user = new User();
        $user->setId($userId);
        $user->setFirstName('first');
        $user->setLastName('last');
        $user->setAge(10);
        $user->validate(); 

Exception:

Swaggest\JsonSchema\Exception\ObjectException : Additional properties not allowed: first_name at #->$ref[#/definitions/MyNamespace\Model\V1\User]
 /srv/www/mypackage/vendor/swaggest/json-schema/src/Schema.php:859
 /srv/www/mypackage/vendor/swaggest/json-schema/src/Schema.php:1139
 /srv/www/mypackage/vendor/swaggest/json-schema/src/Schema.php:195
 /srv/www/mypackage/vendor/swaggest/json-schema/src/Wrapper.php:70
 /srv/www/mypackage/vendor/swaggest/json-schema/src/Structure/ClassStructureTrait.php:152

Am I missed something? Thanx!

vearutop commented 5 years ago

Fixed in https://github.com/swaggest/php-json-schema/releases/tag/v0.12.6