Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

I'm receiving "Class ArrayCollection does not exist" when serializing (temporarily solved with a workaround) #274

Closed
stephenfrank opened this issue May 17, 2014 · 11 comments

Comments

@stephenfrank
Copy link

I saw another issue ticket covering this but the thread included so many topics that didn't help me solve or debug the issue.

I'm receiving this exception when serializing a class with nested collections:

Class ArrayCollection does not exist

27. ReflectionException
…/­vendor/­jms/­metadata/­src/­Metadata/­MetadataFactory.php:167

... and I debugged and breakpointed myself to death and eventually found the code arriving at this point:

JMS\Serializer\EventDispatcher\Subscriber\DoctrineProxySubscriber

// If the set type name is not an actual class, but a faked type for which a custom handler exists, we do not
// modify it with this subscriber. Also, we forgo autoloading here as an instance of this type is already created,
// so it must be loaded if its a real class.
$virtualType = ! class_exists($type['name'], false);

if ($object instanceof PersistentCollection
    || $object instanceof MongoDBPersistentCollection
    || $object instanceof PHPCRPersistentCollection
) {
    if ( ! $virtualType) {
        $event->setType('ArrayCollection');
    }

    return;
}

For anyone who needs to solve this in a hurry and move on with their day, adding this to your bootstrapping/config file will give PHP a chance to find the class:

class_alias('Doctrine\Common\Collections\ArrayCollection', 'ArrayCollection');

Is there any more reasonable way to solving this?

@bazo
Copy link

bazo commented May 17, 2014

do you register any custom handlers? if yes, you need to call addDefaultHandlers on the builder object

@stephenfrank
Copy link
Author

Oh. Okay, slowly the pieces are coming together. I'm trying to add a custom SerializationVisitor which will output a simple array (I'm calling it ArraySerializationVisitor for now).

I see that all of the handlers defined in addDefaultHandler (DateHandler, PhpCollectionHandler, ArrayCollectionHandler and PropelCollectionHandler) all have, in their definition, the set of formats as a hard-coded array:

$formats = array('json', 'xml', 'yml');

This is why when I defined 'array' as a serializer, the handlers were not being used.

Workaround 2:

If I add my ArraySerializationVisitor and call it "json" then it tricks the handlers in to working.

$serializer->setSerializationVisitor('json', new ArraySerializationVisitor(new PropertyNamingStrategy()))

Now everything works as expected.

I suppose one way of fixing this at a library level would be to expose those $format variable as a static variable with getter/setters on each handler so that this can be configured at run-time.

Thoughts?

@alexsegura
Copy link

Same problem here.

Looks like you are not the only one who wants to serialize objects into arrays.

Actually, this is not really a serialization, it's a normalization; but IMHO it should be possible to add Visitors without so much effort. The $formats array shouldn't be hardcoded.

I see another workaround : use SerializeBuilder::configureHandlers and Reflection on HandlerRegistry to call registerHandler with the array format, but it's ugly too !

@LeoBenoist
Copy link

+1 Formats as a hard-coded array: $formats = array('json', 'xml', 'yml'); break option to add a new Serializer

@LeoBenoist
Copy link

Lets go for some extends...:

parameters:
    jms_serializer.datetime_handler.class: YourBundle\Serializer\DateHandler
<?php

namespace YourBundle\Serializer;

use JMS\Serializer\GraphNavigator;
use JMS\Serializer\Handler\DateHandler as BaseDateHandler;

class DateHandler extends BaseDateHandler
{
    /**
     * @return array
     */
    public static function getSubscribingMethods()
    {
        $methods = [];
        $types   = ['DateTime', 'DateInterval'];

        foreach (['json', 'xml', 'yml', 'array'] as $format) {
            $methods[] = [
                'type'      => 'DateTime',
                'direction' => GraphNavigator::DIRECTION_DESERIALIZATION,
                'format'    => $format,
            ];

            foreach ($types as $type) {
                $methods[] = [
                    'type'      => $type,
                    'format'    => $format,
                    'direction' => GraphNavigator::DIRECTION_SERIALIZATION,
                    'method'    => 'serialize'.$type,
                ];
            }
        }

        return $methods;
    }
}

And a simple array serializer

you.array_serialization_visitor:
        class: YourBundle\Serializer\ArraySerializationVisitor
        arguments:
           - @jms_serializer.naming_strategy
        tags:
           - { name: jms_serializer.serialization_visitor, format: array}
<?php

namespace YourBundle\Serializer;

use JMS\Serializer\GenericSerializationVisitor;

class ArraySerializationVisitor extends GenericSerializationVisitor
{
    /**
     * @return array
     */
    public function getResult()
    {
        return $this->getRoot();
    }
}

@goetas
Copy link
Collaborator

goetas commented Aug 3, 2016

can it be related to #517 (comment) ?

@bartosz-zolynski
Copy link

bartosz-zolynski commented Aug 12, 2016

I'm using JMS Serializer with Slim 3 framework for groups so I can easily return the response with desired fields. In this case there's no purpose to encode the result to json in the serializer using "json" method as if I want to attach it to the Slim\Http\Response (PSR-7) using:

$response = $response->withJson($responseData, $responseHttpCode);

then I need to decode it, as it will be encoded in Response::withJson() method again. Performance can suffer for bigger objects as data has been encoded twice, and decoded once, and it obviously makes no sense.

In my opinion, ArraySerializationVisitor (or as I called it, ObjectSerializationVisitor) should be one of the default visitors, and actually this array of methods available, it should be extendable, or - if not - then should be available to retrieve from the single method rather than spread through variety of handlers in getSubscribingMethods() methods (if I'm understanding the purposes of it clearly, but I can be wrong here).

JMS Serializer is really powerful, and I prefer to overwrite "json" method as mentioned above to get the desired result. Actually I was trying to play with PSR-7 StreamInterface thingy, but I still can't get it really (I end up with errors that I can't write to stream, or other weird issues) so actually I don't know how to set the part of the body in other way than by using withJson() for Slim's Response which implements PSR-7 standard.

@goetas
Copy link
Collaborator

goetas commented Aug 12, 2016

Does your application include doctine/common ?

@goetas
Copy link
Collaborator

goetas commented Mar 13, 2017

fixed with c8ad292

@goetas goetas closed this as completed Mar 13, 2017
@stollr
Copy link

stollr commented Jan 30, 2018

@goetas In my case doctrine/common and doctrine/collections is installed, but I still get this error, after upgrading the serializer to 1.10.0.

@stollr
Copy link

stollr commented Jan 30, 2018

I found out, that this error happened in my case because of FriendsOfSymfony/FOSRestBundle#1851

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants