willdurand / Negotiation

Content Negotiation tools for PHP.
https://williamdurand.fr/Negotiation/
MIT License
1.41k stars 62 forks source link

Allow to get a collection of ordered accept headers #75

Closed egeloen closed 7 years ago

egeloen commented 8 years ago

Hey!

Context

We have an API which deals with the Accept-Language header in order to negotiate the best locales to use. In our model we does not priorize locales, we just have a set of locales the application can deal with (not always available) and a default/fallback one (always available).

Use case

We want to use your library to parse and retrieve an order collection of AcceptLanguage if is provided. Then, we can inject this ordered locales in our model which will iterate on provided locales and try to find an available translation transparently. If none exists, we though an exception which will end with a 4xx explaining the reason and the available locales for this specific resource.

Proposal

For now, we was using the 1.x branch of this library and we override the Negotiator to introduce a method which return all ordered locales (not the best one as we don't use priorities). It worked great by using the methods you provided internally such as parseHeader, ...

Now, we just upgrade to the 2.x and we notice that you close the parseHeader method by moving it to private. So, we have to copy/paste your code from the this method to our own and I don't really like it...

Now my code looks like:

public function parse($header)
{
    if (!$header) {
        throw new InvalidArgument('The header string should not be empty.');
    }

    $acceptHeaders = array_map(array($this, 'acceptFactory'), $this->parseHeader($header));

    uasort($acceptHeaders, function (AcceptLanguage $a, AcceptLanguage $b) {
         return $a->getQuality() < $b->getQuality();
    });

    return $acceptHeaders;
}

Basically, I would like to introduce a new method allowing to parse and sort all accept headers without dealing with priorities... Maybe it's out of scope of this library as it is not really a negotiation but much more a parsing/sorting process.

Anyway, I just would like to get your opinion about it as it is something which is handled internally by the library and so can maybe get exposed to end users. Let's if you would accept such change or if I should live with my current code base :)

Cheers!

willdurand commented 8 years ago

Hi!

I'd like to keep as many things private as possible, but if changing visibility from private to protected on a method works for you, I guess we can make an exception. But if I understand correctly, you would like to introduce a new method to the public API. How would you see this feature?

egeloen commented 8 years ago

Basically, instead of letting the negotiator find the best accept header according to a set of priorities, I would have the negotiator be able to parse and order the accept header and then let me negotiate which one my application can use latter.

My application usecase/workflow is I inject this ordered collection of locales (parsed by the negotiator) in my translatable entity on the postLoad doctrine event and then, the translatable entity pick the prefered translation internally according to locales injected.

Then, parsing and ordering accept headers is something this library already does well, so I would like to rely on it... Something like the following would make me in love :)

/**
 * @param string $header The accept header to be parsed.
 *
 * @return AcceptHeader[]
 */
public function parse($header);

What do you think?

egeloen commented 8 years ago

@willdurand What do you think?

willdurand commented 8 years ago

I'm fine with it, show me the code :+1: