public function negotiate(EventInterface $event)
{
$request = $event->getRequest();
$response = $event->getResponse();
$formatter = null;
$extension = $request->getExtension();
$routeName = (string) $request->getRoute();
$config = $event->getConfig();
$contentNegotiateImages = $config['contentNegotiateImages'];
$model = $response->getModel();
if (!$extension && !$contentNegotiateImages && $model instanceof Model\Image) {
// Configuration is telling us not to use content negotiation for images,
// instead we want to use the original format of the image
$mime = $model->getMimeType();
$formatter = $this->supportedTypes[$mime];
} else {
if ($extension && !($model instanceof Model\Error && ($routeName === 'image' || $routeName === 'globalshorturl'))) {
// The user agent wants a specific type. Skip content negotiation completely, but not
// if the request is against the image resource (or the global short url resource), and
// ended up as an error, because then Imbo would try to render the error as an image.
$mime = $this->defaultMimeType;
if (isset($this->extensionsToMimeType[$extension])) {
$mime = $this->extensionsToMimeType[$extension];
}
$formatter = $this->supportedTypes[$mime];
} else {
// Set Vary to Accept since we are doing content negotiation based on Accept
$response->setVary('Accept', false);
// No extension have been provided
$acceptableTypes = [];
foreach (AcceptHeader::fromString($request->headers->get('Accept', '*/*'))->all() as $item) {
$acceptableTypes[$item->getValue()] = $item->getQuality();
}
$match = false;
$maxQ = 0;
// Specify which types to check for since all models can't be formatted by all
// formatters
$modelClass = get_class($model);
$modelType = strtolower(substr($modelClass, strrpos($modelClass, '\\') + 1));
$types = $this->defaultModelTypes;
if (isset($this->modelTypes[$modelType])) {
$types = $this->modelTypes[$modelType];
}
// If we are dealing with images we want to make sure the original mime type of the
// image is checked first. If the client does not really have any preference with
// regards to the mime type (*/* or image/*) this results in the original mime type of
// the image being sent.
if ($model instanceof Model\Image) {
$original = $model->getMimeType();
if ($types[0] !== $original) {
$types = array_filter($types, function ($type) use($original) {
return $type !== $original;
});
array_unshift($types, $original);
}
}
foreach ($types as $mime) {
if (($q = $this->contentNegotiation->isAcceptable($mime, $acceptableTypes)) && $q > $maxQ) {
$maxQ = $q;
$match = true;
$formatter = $this->supportedTypes[$mime];
}
}
if (!$match && !$event->hasArgument('noStrict')) {
// No types matched with strict mode enabled. The client does not want any of Imbo's
// supported types. Y U NO ACCEPT MY TYPES?! FFFFUUUUUUU!
throw new Exception\RuntimeException('Not acceptable', 406);
} else {
if (!$match) {
// There was no match but we don't want to be an ass about it. Send a response
// anyway (allowed according to RFC2616, section 10.4.7)
$formatter = $this->supportedTypes[$this->defaultMimeType];
}
}
}
}
$this->formatter = $formatter;
}