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

PHP Extender: Serializing / forum api attributes #1624

Closed
luceos opened this issue Nov 2, 2018 · 12 comments
Closed

PHP Extender: Serializing / forum api attributes #1624

luceos opened this issue Nov 2, 2018 · 12 comments
Assignees
Milestone

Comments

@luceos
Copy link
Member

luceos commented Nov 2, 2018

Previously in order to append attributes to the forum object in js, one would listen to the Serializing event. This event still exists mind you.

In flagrow/passport I would use this to add an attribute to the ForumSerializer that held the configured button title.

It would be useful to have an extender that allows setting attributes on returned payload. How about an Extend\Serializer class?

    /**
     * @param Serializing $event
     */
    public function prepareApiAttributes(Serializing $event)
    {
        if ($event->isSerializer(ForumSerializer::class)) {
            $event->attributes = array_merge($event->attributes, [
                'flagrow.passport.loginTitle' => $this->settings->get('flagrow.passport.button_title', 'Login')
            ]);
        }
    }
@tobyzerner
Copy link
Contributor

tobyzerner commented Nov 9, 2018

FYI the long term goal for this is to have a new "schema" API to define JSON-API attributes - see the following links:
tobyzerner/json-api-php#126 (comment)
https://gist.github.com/tobscure/5e514a700dcb471180369903ab4562c3

However this will not be ready for a while, in the meantime we can implement something like you've suggested :) Will leave the exact implementation to Franz.

@franzliedke
Copy link
Contributor

I am still hoping we can get close to it with the extender. even before tobscure/json-api sees that new release.

@franzliedke
Copy link
Contributor

@tobscure Now that tobscure/json-api-server is a thing... could you post a proposal of what the extender's signature could look like with the "schema" terminology?

@franzliedke
Copy link
Contributor

(I will then try to implement that signature even with the current code - we will see whether all official extensions' use-cases can then be mapped to that concept already.)

@tobyzerner
Copy link
Contributor

Basically:

    new Extend\Api('posts', function (Builder $schema) {
        // extend schema as per tobscure/json-api-server
    }),

We also need a way to register new resource types, which is the same but also need to specify an adapter. Maybe just a third param:

    new Extend\Api('posts', function (Builder $schema) {
        // build schema as per tobscure/json-api-server
    }, new EloquentAdapter(new Post)),

@franzliedke
Copy link
Contributor

Cheers, will try it out. Until tobscure/json-api-server is integrated, I'll probably provide an alternative implementation of the schema builder (which maps to the current constructs), which means no type-hint in the closure for now.

@luceos
Copy link
Member Author

luceos commented Mar 22, 2019

My current serializing extender:

<?php

namespace Flagrow\Byobu\Extend;

use Flarum\Api\Event\Serializing;
use Flarum\Extend\ExtenderInterface;
use Flarum\Extension\Extension;
use Illuminate\Contracts\Container\Container;
use Illuminate\Contracts\Events\Dispatcher;

class ApiAttribute implements ExtenderInterface
{
    protected $mutations = [];

    public function extend(Container $container, Extension $extension = null)
    {
        /** @var Dispatcher $events */
        $events = $container->make(Dispatcher::class);

        $events->listen(Serializing::class, function (Serializing $event) use ($container) {
            foreach ($this->mutations as $mutation) {
                list($serializer, $callable) = $mutation;

                if ($event->isSerializer($serializer)) {
                    $callable = $container->make($callable);
                    $callable($event);
                }
            }
        });
    }

    public function add(string $serializer, $callable)
    {
        $this->mutations[] = [$serializer, $callable];

        return $this;
    }
}

Used in extend.php:

    (new Extend\ApiAttribute)
        ->add(BasicUserSerializer::class, Api\UserAttributes::class),

Where the second argument is an invokable class:

<?php

namespace Flagrow\Byobu\Api;

use Flarum\Api\Event\Serializing;
use Flarum\Api\Serializer\BasicUserSerializer;
use Flarum\User\User;

class UserAttributes
{
    /**
     * @param Serializing $event
     */
    public function __invoke(Serializing $event)
    {
            /** @var User $user */
            $user = $event->model;
            $event->attributes['blocksPd'] = $user->getPreference('blocksPd', false);
    }
}

@franzliedke
Copy link
Contributor

Oh nice, that would even give us support for cases like this one.

Do we want to go with this now as a stop-gap solution? It will have to be deprecated as we move towards the "schema" approach, though.

@luceos
Copy link
Member Author

luceos commented Mar 22, 2019

It will have to be deprecated as we move towards the "schema" approach, though.

@franzliedke Yeah but that was to be expected, I think it's fine. The benefit of having the extenders in core (before too many extensions adopt their own) is that we can globally deprecate them first and then remove them.

@tobyzerner
Copy link
Contributor

I think I would rather try and emulate the schema API as close as possible as a stop-gap

@MichaelBelgium
Copy link

MichaelBelgium commented Jan 17, 2020

I actually needed something like this! Passing the extension settings to the forum front-end.

Would be very helpful if an extender like this gets implemented or an alternative that passes settings to admin/forum front-end at the same time.

Currently this can be done in beta 11 but a lot of people wanna do the same and the event isn't the purpose of it i guess:

use Flarum\Api\Event\Serializing;
use Illuminate\Contracts\Events\Dispatcher;
use Flarum\Settings\SettingsRepositoryInterface;

class SettingsToForum
{
    private $settings;

    public function __construct(SettingsRepositoryInterface $settings) {
        $this->settings = $settings;
    }

    public function subscribe(Dispatcher $events)
    {
        $events->listen(Serializing::class, [$this, 'addSettings']);
    }

    public function addSettings(Serializing $event)
    {
        $event->attributes['mb-discussionviews.show_filter'] = $this->settings->get('michaelbelgium-discussionviews.show_filter', true);
        $event->attributes['mb-discussionviews.abbr_numbers'] = $this->settings->get('michaelbelgium-discussionviews.abbr_numbers', false);
    }
} 

@franzliedke
Copy link
Contributor

@MichaelBelgium Thanks for mentioning it.

I must admit I've been avoiding this one a little bit, but I know that it's going to be one of the most useful extenders, at least when judging by our own bundled extensions.

The thing is, different extensions use quite a few different data sources when extending our various endpoints that I haven't yet found a nice API for it. But I know I need to tackle it soon, if we want to make any progress in the extender area at all.

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

No branches or pull requests

6 participants