web-dev-qa-db-fra.com

JMSSerializer stand alone - L'annotation n'existe pas ou ne peut pas être chargée automatiquement

J'essaie d'utiliser JMSSerializer en tant que bibliothèque autonome pour mapper les réponses JSON d'une API à mes classes de modèle et rencontre certains problèmes.

L'exécution du code suivant génère une exception:

<?php
require dirname(__DIR__) . '/vendor/autoload.php';

use JMS\Serializer\Annotation AS JMS;

class Trii {
    /**
     * User ID for this session
     * @JMS\SerializedName("userID")
     * @JMS\Annotation(getter="getUserId")
     * @JMS\Type("string")
     * @var string
     */
    private $userId;

    public function getUserId() {
        return $this->userId;
    }

    public function setUserId($userId) {
        $this->userId = $userId;
    }
}

$serializer = \JMS\Serializer\SerializerBuilder::create()->setDebug(true)->build();
$object = $serializer->deserialize('{"userID":"Trii"}', 'Trii', 'json');
var_dump($object);
?>

Voici l'exception

Doctrine\Common\Annotations\AnnotationException: [Semantical Error] The annotation "@JMS\Serializer\Annotation\SerializedName" in property Trii::$userId does not exist, or could not be auto-loaded.

J'ai les bibliothèques suivantes installées pour le projet via composer

{
    "require": {
        "jms/serializer": "1.0.*@dev"
    }
}

Y a-t-il quelque chose d'évident qui me manque puisque je n'utilise pas toute la solution Doctrine 2?

EDIT: ma solution finale a été de créer un fichier de démarrage avec le contenu suivant:

<?php
// standard composer install vendor autoload magic
require dirname(__DIR__) . '/vendor/autoload.php';

// Bootstrap the JMS custom annotations for Object to Json mapping
\Doctrine\Common\Annotations\AnnotationRegistry::registerAutoloadNamespace(
    'JMS\Serializer\Annotation',
    dirname(__DIR__).'/vendor/jms/serializer/src'
);
?>
33
Josh J

Cela garantit le chargement automatique silencieux, ce qui est beaucoup plus pratique que d’enregistrer vous-même les espaces de noms.

AnnotationRegistry::registerLoader('class_exists');
68
Flip

J'ai rencontré le même problème et j'ai trouvé votre question via Google. Malheureusement, vous n'avez pas encore reçu de réponse, j'ai donc dû creuser moi-même. : P 

En fait, Doctrine Annotations, utilisé par JMSSerializer Annotations, n'utilise PAS l'autoloading PHP normal

Comment ces annotations sont-elles chargées? En regardant le code, vous pouvez deviner que le mappage ORM, la validation d'assertion et l'annotation complète peuvent simplement être chargés à l'aide des autochargeurs PHP définis. Ce n'est cependant pas le cas: pour des raisons de gestion des erreurs, chaque vérification de l'existence d'une classe dans AnnotationReader définit le deuxième paramètre $ autoload de class_exists ($ name, $ autoload) sur false. Pour fonctionner parfaitement, AnnotationReader requiert des autochargeurs automatiques silencieux, contrairement à la plupart des autoloaders. Le chargement automatique silencieux ne fait PAS partie de la spécification PSR-0 pour le chargement automatique.

Cela signifie que vous devez enregistrer le (s) fichier (s) d'annotation vous-même:

AnnotationRegistry::registerFile(
   <PROJECT ROOT> . 
   "/vendor/jms/serializer/src/JMS/Serializer/Annotation/SerializedName.php");

... ou tout l'espace de noms (méthode préférée):

AnnotationRegistry::registerAutoloadNamespace(
    'JMS\Serializer\Annotation', 
    <PROJECT ROOT> . "/vendor/jms/serializer/src");

Soyez prudent avec le chemin dans registerAutoloadNamespace. J'ai d'abord essayé d'enregistrer le chemin d'accès complet aux annotations de la même manière avec registerFile:

<PROJECT ROOT> . "/vendor/jms/serializer/src/JMS/Serializer/Annotation 

mais cela a lamentablement échoué. :RÉ

J'espère que cela vous fera avancer un peu plus loin. :)

40
SirArturio

@SirArturio a la bonne réponse à ce casse-tête de chargement automatique, et je voulais simplement ajouter une touche de clarté en réponse à @messified ou à toute autre personne qui lutte pour que cela fonctionne. Comme il l'a expliqué avec éloquence, le gestionnaire automatique PSR-0 dans composer, ou SPL, ne va pas le couper pour charger ces annotations, car ils utilisent le chargement automatique de Doctrine.

Voici donc un petit exemple complet. Chaque fois que vous créez votre objet Sérialiseur JMS pour commencer la sérialisation, c'est un bon moment pour ajouter l'espace de nom d'annotation à l'autoloader de la doctrine. Par souci de clarté, je suppose qu’il n’ya pas d’IoC ni d’espaces de noms pleinement qualifiés (indice, astuce, utiliser une dépendance):

<?php
Doctrine\Common\Annotations\AnnotationRegistry::registerAutoloadNamespace(
'JMS\Serializer\Annotation', 
$your_app_basepath . "/vendor/jms/serializer/src");


$serializer = JMS\Serializer\SerializerBuilder::create()->build();
$json_output = $serializer->serialize('MyProject\MyClass', 'json');

Puis dans votre MyProject\MyClass:

<?php
use JMS\Serializer\Annotation as JMS;

class MyClass{

    /** @JMS\Exclude */
    private $something_secret;
}

Et cela devrait le couper, charger automatiquement le fichier d'annotation approprié en utilisant doctrine au lieu de composeur.

4
jpschroeder

Vérifiez la capitalisation de vos annotations. J'ai eu un problème similaire lors du déploiement d'un environnement Windows dev sur un serveur Ubuntu, qui était dû à une faute de frappe dans le cas de mon annotation. Les fichiers Windows ne font pas la distinction entre les majuscules et les minuscules, de sorte que cela fonctionne mais échoue sous Linux.

3
Tamlyn

Si vous utilisez Composer, vous pouvez obtenir le chargeur en spécifiant un chemin dans require:

$loader = require(__DIR__ . '/../vendor/autoload.php');
AnnotationRegistry::registerLoader(array($loader, 'loadClass'));
0
Lebnik