schmittjoh / JMSSerializerBundle

Easily serialize, and deserialize data of any complexity (supports XML, JSON, YAML)
http://jmsyst.com/bundles/JMSSerializerBundle
MIT License
1.8k stars 313 forks source link

JMSSerializerBundle configuration Metadata (2) #650

Closed aayaresko closed 6 years ago

aayaresko commented 6 years ago

hello. first of all: thanks a lot for this wonderful bundle. it's very useful. I have an issue with jms/serializer-bundle: 2.3.1 and symfony 4.0.6. When react app retrieves the data, it receives empty objects:

[
    0: {},
    1: {},
    2: {},
    3: {},
    4: {},
]

Here's the content of jms_serializer.yaml

jms_serializer:
    metadata:
        cache: file
        debug: '%kernel.debug%'
        file_cache:
            dir: '%kernel.cache_dir%/serializer'
        auto_detection: false
        directories:
            app:
                namespace_prefix: "App\\Entity"
                path: "%kernel.root_dir%/Resources/config/serializer"
    property_naming:
        separator:  _
        lower_case: true
    handlers:
        datetime:
            default_format: 'Y-m-d\TH:i:sO'
            default_timezone: 'UTC'

Here is my song entity serialization config (src/Resources/config/serializer/Entity.Song.yml)

App\Entity\Song:
    exclusion_policy: ALL
    properties:
        id:
            expose: true
            groups: [view_default, view_detailed]
        aliasName:
            expose: true
            groups: [view_default, view_detailed]
        file:
            expose: true
            groups: [view_default, view_detailed]
        createdAt:
            expose: true
            groups: [view_detailed]
        deletedAt:
            expose: true
            groups: [view_detailed]
        tags:
            expose: true
            groups: [view_detailed]
        playLists:
            expose: true
            groups: [view_detailed]
    virtual_properties:
        getName:
            serialized_name: name
            type: string
            groups: [view_default, view_detailed]
        getArtist:
            serialized_name: artist
            type: string
            groups: [view_default, view_detailed]
        getWebPath:
            serialized_name: web_path
            type: string
            groups: [view_default, view_detailed]

Controller

<?php

namespace App\Controller\API;

use App\Entity\PlayList\PlayList;
use App\Entity\Song\SongTag;
use App\Repository\Song\SongTagRepository;
use App\Service\PlayListService;
use FOS\RestBundle\Controller\Annotations as Rest;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;

/**
 * @Rest\Route("user")
 */
class SongController extends ApiController
{
    /**
     * @Rest\Get("/play-list/{id}/song", name="api.user.play_list.song")
     *
     * @param PlayList $entity
     * @return Response
     */
    public function playListSongs(PlayList $entity)
    {
        /** @var PlayListService $service */
        $service = $this->get(PlayListService::class);
        $view    = $this->view($service->retrieveSongs($entity), Response::HTTP_OK, ['view_default']);

        return $this->handleView($view);
    }
}

I have no idea why it doesn't work. It worked fine with model annotations but completely broken now, with yml configs. Need some help :) Thanks in advance.

ps: bundle is enabled (bundles.php); all steps, described in #536 are done and checked without any success

goetas commented 6 years ago

From what I remember, the third parameter in the view method are the http headers, not the groups. Groups have to be set later on the view object

aayaresko commented 6 years ago

@goetas thank you for your response, good point. we use a wrapper method in ApiController. the method builds a view (just like you've described) then creates a context adds groups and setContext of the view. Here's the view instance gets created in SongController::playListSongs

<pre class='xdebug-var-dump' dir='ltr'>
<small>/src/Controller/API/SongController.php:29:</small>
<b>object</b>(<i>FOS\RestBundle\View\View</i>)[<i>746</i>]
  <i>private</i> 'data' <font color='#888a85'>=&gt;</font> 
    <b>object</b>(<i>Doctrine\Common\Collections\ArrayCollection</i>)[<i>709</i>]
      <i>private</i> 'elements' <font color='#888a85'>=&gt;</font> 
        <b>array</b> <i>(size=5)</i>
          0 <font color='#888a85'>=&gt;</font> 
            <b>object</b>(<i>Proxies\__CG__\App\Entity\Song\Song</i>)[<i>759</i>]
              ...
          1 <font color='#888a85'>=&gt;</font> 
            <b>object</b>(<i>Proxies\__CG__\App\Entity\Song\Song</i>)[<i>757</i>]
              ...
          2 <font color='#888a85'>=&gt;</font> 
            <b>object</b>(<i>Proxies\__CG__\App\Entity\Song\Song</i>)[<i>755</i>]
              ...
          3 <font color='#888a85'>=&gt;</font> 
            <b>object</b>(<i>Proxies\__CG__\App\Entity\Song\Song</i>)[<i>753</i>]
              ...
          4 <font color='#888a85'>=&gt;</font> 
            <b>object</b>(<i>Proxies\__CG__\App\Entity\Song\Song</i>)[<i>745</i>]
              ...
  <i>private</i> 'statusCode' <font color='#888a85'>=&gt;</font> <small>int</small> <font color='#4e9a06'>200</font>
  <i>private</i> 'templateData' <font color='#888a85'>=&gt;</font> 
    <b>array</b> <i>(size=0)</i>
      <i><font color='#888a85'>empty</font></i>
  <i>private</i> 'template' <font color='#888a85'>=&gt;</font> <font color='#3465a4'>null</font>
  <i>private</i> 'templateVar' <font color='#888a85'>=&gt;</font> <small>string</small> <font color='#cc0000'>'data'</font> <i>(length=4)</i>
  <i>private</i> 'engine' <font color='#888a85'>=&gt;</font> <font color='#3465a4'>null</font>
  <i>private</i> 'format' <font color='#888a85'>=&gt;</font> <font color='#3465a4'>null</font>
  <i>private</i> 'location' <font color='#888a85'>=&gt;</font> <font color='#3465a4'>null</font>
  <i>private</i> 'route' <font color='#888a85'>=&gt;</font> <font color='#3465a4'>null</font>
  <i>private</i> 'routeParameters' <font color='#888a85'>=&gt;</font> <font color='#3465a4'>null</font>
  <i>private</i> 'context' <font color='#888a85'>=&gt;</font> 
    <b>object</b>(<i>FOS\RestBundle\Context\Context</i>)[<i>707</i>]
      <i>private</i> 'attributes' <font color='#888a85'>=&gt;</font> 
        <b>array</b> <i>(size=0)</i>
          <i><font color='#888a85'>empty</font></i>
      <i>private</i> 'version' <font color='#888a85'>=&gt;</font> <font color='#3465a4'>null</font>
      <i>private</i> 'groups' <font color='#888a85'>=&gt;</font> 
        <b>array</b> <i>(size=1)</i>
          0 <font color='#888a85'>=&gt;</font> <small>string</small> <font color='#cc0000'>'view_default'</font> <i>(length=12)</i>
      <i>private</i> 'maxDepth' <font color='#888a85'>=&gt;</font> <font color='#3465a4'>null</font>
      <i>private</i> 'isMaxDepthEnabled' <font color='#888a85'>=&gt;</font> <font color='#3465a4'>null</font>
      <i>private</i> 'serializeNull' <font color='#888a85'>=&gt;</font> <font color='#3465a4'>null</font>
      <i>private</i> 'exclusionStrategies' <font color='#888a85'>=&gt;</font> 
        <b>array</b> <i>(size=0)</i>
          <i><font color='#888a85'>empty</font></i>
  <i>private</i> 'response' <font color='#888a85'>=&gt;</font> <font color='#3465a4'>null</font>
</pre>

as you can see, groups are there.

goetas commented 6 years ago

Pay attention that if the prefix namespace us app\entity, the metadata file should be just named sing.yml not entity.song.yml

goetas commented 6 years ago

Do not forget to clear the cachr

aayaresko commented 6 years ago

@goetas okay. I renamed the file src/Resources/config/serializer/Entity.Song.yml -> src/Resources/config/serializer/Song.yml - that doesn't help. should I use lower case for file name? yes, of course, I clear cache every time I make changes in configs.

goetas commented 6 years ago

Do you know mind checking if this https://github.com/schmittjoh/metadata/blob/4f1cd28ff9cc156d06bd25df401369a3d64150f3/src/Metadata/Driver/AbstractFileDriver.php#L24 line of code is ever reached? And ckeck the value of the $path variable (is the file that jms will try to load for the metadata extraction)

aayaresko commented 6 years ago

@goetas, the $path is null and the $class is Doctrine\Common\Collections\ArrayCollection.

/vendor/jms/metadata/src/Metadata/Driver/AbstractFileDriver.php:26:null
object(ReflectionClass)[772]
  public 'name' => string 'Doctrine\Common\Collections\ArrayCollection' (length=43)
goetas commented 6 years ago

So, retrieveSongs is returning an arraycollection, have you tried converting it to an array?

aayaresko commented 6 years ago

@goetas here what I get when I convert the result to an array:

/vendor/jms/metadata/src/Metadata/Driver/AbstractFileDriver.php:26:null

/vendor/jms/metadata/src/Metadata/Driver/AbstractFileDriver.php:26:
object(ReflectionClass)[779]
  public 'name' => string 'App\Entity\Song\Song' (length=20)

the Song entity is indeed located in src/Entity/Song/ directory. and the response still contains empty objects.

goetas commented 6 years ago

Ok.means the file is not found. You can debug this method https://github.com/schmittjoh/metadata/blob/4f1cd28ff9cc156d06bd25df401369a3d64150f3/src/Metadata/Driver/FileLocator.php#L25 to check all the paths the serializer is trying

aayaresko commented 6 years ago

@goetas okay, and here's what I have got from $path = $dir.'/'.str_replace('\', '.', substr($class->name, $len)).'.'.$extension:

src/Resources/config/serializer/Song.Song.yml
goetas commented 6 years ago

Something is wrong, "%kernel.root_dir% should be an absolute path, not relative

aayaresko commented 6 years ago

yes it is. sorry, I removed some parts, here what it looks like:

/srv/aayaresko/public_html/www/symfony/mplay_list/application/src/Resources/config/serializer/Song.Song.yml
aayaresko commented 6 years ago

@goetas I found what causes the issue! the thing is that my Entity directory does contains sub directories: Song and PlayList

goetas commented 6 years ago

Ah, ok. so, your entity is called App\Entity\Song\Song, so your metadata file should be Resources/config/serializer/Song.Song.yml, while from what I can see was src/Resources/config/serializer/Entity.Song.yml and later you renamed it into src/Resources/config/serializer/Song.yml

aayaresko commented 6 years ago

yes, correct. thanks a lot for your help!

smuralidharan commented 5 years ago

I got the same issue, i tried all the possible solutions but not works. Please help!

smuralidharan commented 5 years ago

Do you know mind checking if this https://github.com/schmittjoh/metadata/blob/4f1cd28ff9cc156d06bd25df401369a3d64150f3/src/Metadata/Driver/AbstractFileDriver.php#L24 line of code is ever reached? And ckeck the value of the $path variable (is the file that jms will try to load for the metadata extraction)

@goetas Got same issue, the line of code is not reached for me . Please help

goetas commented 5 years ago

As you can read here, each issue was related to typos in path names or classes, so please carefully check the various paths and namespaces

smuralidharan commented 5 years ago

@goetas Yes i thought the same, inside app/config/config.yml we have this code under jms_serializer: namespace_prefix: "Just\Captive\CoreBundle\Entity\User"

I got Found unknown escape character "\C" at line 190 (near "namespace_prefix: error

but if i give without double quotes no error shown. Please assist

goetas commented 5 years ago

Just use single quotes

On Mon, 21 Jan 2019, 07:54 smuralidharan <notifications@github.com wrote:

@goetas https://github.com/goetas Yes i thought the same, inside app/config/config.yml we have this code under jms_serializer: namespace_prefix: "Just\Captive\CoreBundle\Entity\User"

I got Found unknown escape character "\C" at line 190 (near "namespace_prefix: error

but if i give without double quotes no error shown. Please assist

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/schmittjoh/JMSSerializerBundle/issues/650#issuecomment-455965785, or mute the thread https://github.com/notifications/unsubscribe-auth/AAvaJxtaTmfUELrpm1ERJfno1vEhYxEMks5vFWQ8gaJpZM4TXAiY .

smuralidharan commented 5 years ago

@goetas

Now i don't get any error but the line of code below is still not reached . Any other way to debug this issue?

https://github.com/schmittjoh/metadata/blob/4f1cd28ff9cc156d06bd25df401369a3d64150f3/src/Metadata/Driver/AbstractFileDriver.php#L24

Just use single quotes On Mon, 21 Jan 2019, 07:54 smuralidharan @.*** wrote: @goetas https://github.com/goetas Yes i thought the same, inside app/config/config.yml we have this code under jms_serializer: namespace_prefix: "Just\Captive\CoreBundle\Entity\User" I got Found unknown escape character "\C" at line 190 (near "namespace_prefix: error but if i give without double quotes no error shown. Please assist — You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub <#650 (comment)>, or mute the thread https://github.com/notifications/unsubscribe-auth/AAvaJxtaTmfUELrpm1ERJfno1vEhYxEMks5vFWQ8gaJpZM4TXAiY .

webdevilopers commented 5 years ago

I struggled with XML metadata too until I realized I was making the same mistake as mentioned by @mehdi-zarrin :

https://github.com/schmittjoh/JMSSerializerBundle/issues/686#issuecomment-425835037

$serializer = $this->get('jms_serializer');

Maybe this helps!