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

[Question] CamelCasing included relationships #343

Open
renspoesse opened this issue Nov 21, 2016 · 9 comments
Open

[Question] CamelCasing included relationships #343

renspoesse opened this issue Nov 21, 2016 · 9 comments
Labels

Comments

@renspoesse
Copy link

renspoesse commented Nov 21, 2016

I'm trying to include a relationship and CamelCase its key in the output. Is there a way to do this in Fractal without altering the function name in the model?

Model:

class Project extends Model
{
    public function target_locations()
    {
        return $this->belongsToMany('Location');
    }
}

Transformer:

class ProjectTransformer extends TransformerAbstract
{    
    protected $defaultIncludes = ['target_locations'];

    public function transform(Project $obj)
    {
        return [

            'id' => (int)$obj->id
        ];
    }

    public function includeTargetLocations(Project $obj)
    {
        return $obj->target_locations ? $this->collection($obj->target_locations, new LocationTransformer()) : null;
    }
}

The JSON output that I'd like:

{
    id: 1,
    targetLocations: []
}

Thanks in advance for any answer!

@bradbforbes
Copy link

This is a bit tricky if you don't want to change $defaultIncludes.

You could do a quick extending serializer like this:

class CamelCaseArraySerializer extends ArraySerializer
{
    /**
     * Serialize a collection.
     *
     * @param string $resourceKey
     * @param array  $data
     *
     * @return array
     */
    public function collection($resourceKey, array $data)
    {
        return parent::collection($resourceKey, $this->convertKeysToCamelCase($data));
    }

    /**
     * Serialize an item.
     *
     * @param string $resourceKey
     * @param array  $data
     *
     * @return array
     */
    public function item($resourceKey, array $data)
    {
        return parent::item($resourceKey, $this->convertKeysToCamelCase($data));
    }

    /**
     * Convert keys of an array from snake to camel case.
     *
     * @param $data
     * @return array
     */
    private function convertKeysToCamelCase($data) {
        $keys = array_map(function ($i) {
            $parts = explode('_', $i);
            return array_shift($parts). implode('', array_map('ucfirst', $parts));
        }, array_keys($data));

        return array_combine($keys, $data);
    }
}

Then pass it to the manager like this:
$manager = (new Manager())->setSerializer(new CamelCaseArraySerializer());

But this will camel case all of the keys, and you may just want to camel case included resource keys? This may be hard to do without giving the serializer a list of keys to only look for, specific to your application. But there may be an option I'm not thinking of that someone else can chime in with.

@renspoesse
Copy link
Author

Hey Brad! I've adapted your serializer but it doesn't seem to work for included items. Though even if it did, wouldn't this fix the problem at the "wrong" level? I.e., at serialization level instead of transformation level.

@greydnls
Copy link
Contributor

@renspoesse you should be able to change the key in $default_includes to camel case and have it work. Have you tried that?

@bradbforbes
Copy link

Sorry about that -- it looks like I forgot a filterIncludes() override in my serializer, but it would be implemented in the same fashion as the other methods if you decided to use it.

I agree with you about this being more appropriate in the transformation domain, but I'm not sure how it could be done easily. If you take a look at TransformerAbstract::includeResourceIfAvailable(), you'll see that it's really the $default_includes/$available_includes strings that dictate the key names you want to camel case. You could extend TransformerAbstract and override includeResourceIfAvailable() in a transformer that your model transformers then implement, but then you're overriding a private method implied to be "final." Though I may be missing another option that someone else can point out.

@renspoesse
Copy link
Author

@bradbforbes thanks, we've extended TransformerAbstract to fix it (for now)!

You're right though, we had to override a private method so I still think this is a bit of an issue in flexibility of the transformer.

@KieronWiltshire
Copy link

Any solution to this yet?

@minhtamwebmaster
Copy link

same problem

image

i want convert to underscore

@stale
Copy link

stale bot commented Apr 16, 2022

This issue has been automatically marked as stale because it has not had recent activity. It will be closed after 4 weeks if no further activity occurs. Thank you for your contributions.

@stale stale bot added the stale label Apr 16, 2022
@illusi03
Copy link

I have solved this issue, by force include (available or default) with underscored attributes. Because laravel has automate convert camelCase into snake-case in all attributes (getter)
For example,
image

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

No branches or pull requests

6 participants