2017-01-14 17:36:56 +01:00
< ? php
/*
* This file is part of the NelmioApiDocBundle package .
*
* ( c ) Nelmio
*
* For the full copyright and license information , please view the LICENSE
* file that was distributed with this source code .
*/
namespace Nelmio\ApiDocBundle\ModelDescriber ;
2018-01-24 19:58:38 +01:00
use Doctrine\Common\Annotations\Reader ;
2017-01-14 17:36:56 +01:00
use EXSyst\Component\Swagger\Schema ;
use Nelmio\ApiDocBundle\Describer\ModelRegistryAwareInterface ;
use Nelmio\ApiDocBundle\Describer\ModelRegistryAwareTrait ;
use Nelmio\ApiDocBundle\Model\Model ;
2018-01-24 19:58:38 +01:00
use Nelmio\ApiDocBundle\ModelDescriber\Annotations\AnnotationsReader ;
2017-01-14 17:36:56 +01:00
use Symfony\Component\PropertyInfo\PropertyInfoExtractorInterface ;
use Symfony\Component\PropertyInfo\Type ;
class ObjectModelDescriber implements ModelDescriberInterface , ModelRegistryAwareInterface
{
use ModelRegistryAwareTrait ;
2017-03-15 12:33:05 +01:00
private $propertyInfo ;
2018-01-24 19:58:38 +01:00
private $annotationsReader ;
2017-12-03 20:30:44 +02:00
2018-01-24 15:20:20 +01:00
private $swaggerDefinitionAnnotationReader ;
2017-12-03 20:30:44 +02:00
public function __construct (
PropertyInfoExtractorInterface $propertyInfo ,
2018-01-24 19:58:38 +01:00
Reader $reader
2017-12-17 10:44:07 +01:00
) {
2017-01-14 17:36:56 +01:00
$this -> propertyInfo = $propertyInfo ;
2018-01-24 19:58:38 +01:00
$this -> annotationsReader = new AnnotationsReader ( $reader );
2017-01-14 17:36:56 +01:00
}
public function describe ( Model $model , Schema $schema )
{
$schema -> setType ( 'object' );
$properties = $schema -> getProperties ();
$class = $model -> getType () -> getClassName ();
2017-06-13 13:34:26 +02:00
$context = [];
if ( null !== $model -> getGroups ()) {
$context = [ 'serializer_groups' => $model -> getGroups ()];
}
2018-01-24 19:58:38 +01:00
$this -> annotationsReader -> updateDefinition ( new \ReflectionClass ( $class ), $schema );
2017-06-13 13:34:26 +02:00
$propertyInfoProperties = $this -> propertyInfo -> getProperties ( $class , $context );
2017-03-15 12:33:05 +01:00
if ( null === $propertyInfoProperties ) {
return ;
}
2017-05-31 18:35:02 +02:00
2017-03-15 12:33:05 +01:00
foreach ( $propertyInfoProperties as $propertyName ) {
2018-01-11 12:26:59 +01:00
$property = $properties -> get ( $propertyName );
// read property options from Swagger Property annotation if it exists
if ( property_exists ( $class , $propertyName )) {
2018-01-24 19:58:38 +01:00
$this -> annotationsReader -> updateProperty (
2018-01-11 12:26:59 +01:00
new \ReflectionProperty ( $class , $propertyName ),
$property
);
}
// If type manually defined
if ( null !== $property -> getType ()) {
continue ;
}
2017-01-14 17:36:56 +01:00
$types = $this -> propertyInfo -> getTypes ( $class , $propertyName );
if ( 0 === count ( $types )) {
throw new \LogicException ( sprintf ( 'The PropertyInfo component was not able to guess the type of %s::$%s' , $class , $propertyName ));
}
if ( count ( $types ) > 1 ) {
throw new \LogicException ( sprintf ( 'Property %s::$%s defines more than one type.' , $class , $propertyName ));
}
2017-12-03 20:30:44 +02:00
$type = $types [ 0 ];
if ( Type :: BUILTIN_TYPE_ARRAY === $type -> getBuiltinType ()) {
$type = $type -> getCollectionValueType ();
2018-01-11 12:26:59 +01:00
if ( null === $type ) {
throw new \LogicException ( sprintf ( 'Property "%s:%s" is an array, but no indication of the array elements are made. Use e.g. string[] for an array of string.' , $class , $propertyName ));
}
2017-12-03 20:30:44 +02:00
$property -> setType ( 'array' );
$property = $property -> getItems ();
}
2017-12-17 10:44:07 +01:00
if ( Type :: BUILTIN_TYPE_STRING === $type -> getBuiltinType ()) {
2017-12-03 20:30:44 +02:00
$property -> setType ( 'string' );
2017-12-17 10:44:07 +01:00
} elseif ( Type :: BUILTIN_TYPE_BOOL === $type -> getBuiltinType ()) {
2017-12-03 20:30:44 +02:00
$property -> setType ( 'boolean' );
2017-12-17 10:44:07 +01:00
} elseif ( Type :: BUILTIN_TYPE_INT === $type -> getBuiltinType ()) {
2017-12-03 20:30:44 +02:00
$property -> setType ( 'integer' );
2017-12-17 10:44:07 +01:00
} elseif ( Type :: BUILTIN_TYPE_FLOAT === $type -> getBuiltinType ()) {
2017-12-03 20:30:44 +02:00
$property -> setType ( 'number' );
$property -> setFormat ( 'float' );
2017-12-17 10:44:07 +01:00
} elseif ( Type :: BUILTIN_TYPE_OBJECT === $type -> getBuiltinType ()) {
2017-12-03 20:30:44 +02:00
if ( in_array ( $type -> getClassName (), [ 'DateTime' , 'DateTimeImmutable' ])) {
$property -> setType ( 'string' );
$property -> setFormat ( 'date-time' );
} else {
$property -> setRef (
$this -> modelRegistry -> register ( new Model ( $type , $model -> getGroups ()))
);
}
} else {
2017-12-17 10:44:07 +01:00
throw new \Exception ( sprintf ( 'Unknown type: %s' , $type -> getBuiltinType ()));
2017-12-03 20:30:44 +02:00
}
2017-01-14 17:36:56 +01:00
}
}
2017-03-17 19:37:41 +01:00
public function supports ( Model $model ) : bool
2017-01-14 17:36:56 +01:00
{
return Type :: BUILTIN_TYPE_OBJECT === $model -> getType () -> getBuiltinType ();
}
}