oEmbed in Symfony 3 implementation

615 views Asked by At

I want to allow user creating oEmbed content to my website. There is a lot of information how to implement it but none about creating a enpoint.

  1. Quick question: is there some ready php code samples for creating (returning) oEmbed response for third party websites?

  2. If no, how to create it? Ex youtube link looks like this:

    http://www.youtube.com/oembed?url=http%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DiwGFalTRHDA

    and the response is :

    {
        "html": "<iframe width=\"459\" height=\"344\" src=\"https://www.youtube.com/embed/iwGFalTRHDA?feature=oembed\" frameborder=\"0\" allowfullscreen></iframe>",
        "thumbnail_height": 360,
        "thumbnail_width": 480,
        "provider_name": "YouTube",
        "author_url": "https://www.youtube.com/user/KamoKatt",
        "thumbnail_url": "https://i.ytimg.com/vi/iwGFalTRHDA/hqdefault.jpg",
        "author_name": "KamoKatt",
        "provider_url": "https://www.youtube.com/",
        "type": "video",
        "version": "1.0",
        "width": 459,
        "title": "Trololo",
        "height": 344
    }
    

    My question is: how they know which video it is? They are using regexp to parse videoID?

  3. What is 'best practice' for this kind of request? Should it be created as Controller, Service, Provider or how?

1

There are 1 answers

0
breq On BEST ANSWER

Finally I have created it like this:

  1. I have created a service:

namespace AppBundle\Service;

use AppBundle\Entity\PlaceMarker;
use Doctrine\ORM\EntityManager;
use Symfony\Component\Config\Definition\Exception\Exception;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Exception as Ex;
use Symfony\Component\Routing\Matcher\UrlMatcher;
use Symfony\Component\Routing\RequestContext;
use Symfony\Component\Routing\Route;
use Symfony\Component\Routing\RouteCollection;


class EmbedService
{

    CONST THUMBNAIL_WIDTH = 400;
    CONST THUMBNAIL_HEIGHT = 300;
    CONST HTML_WIDTH = 459;
    CONST HTML_HEIGHT = 344;

    /**
     * @var string
     */
    protected $baseUrl;

    /**
     * @var array
     */
    private $params = [];

    /**
     * @var EntityManager
     */
    private $entityManager;

    /** @var \Twig_Environment */
    private $twig;

    public function __construct($baseUrl, EntityManager $entityManager, \Twig_Environment $twig)
    {
        $this->baseUrl = strtolower($baseUrl);
        $this->entityManager = $entityManager;
        $this->twig = $twig;
    }

    /**
     *
     * @param Request $request
     * @param null $format
     * @throws \Exception
     */
    public function handleRequest(Request $request, $format = null)
    {
        $this->params = [];

//        $baseUrl = $request->getSchemeAndHttpHost();

        /** handle url parameter */
        $this->params['url'] = $request->query->get('url');
        if (!$this->params['url']) {
            throw new Ex\BadRequestHttpException('A URL parameter must be provided');
        }

        /** check if url matches site url */
        $this->params['path'] = substr($request->query->get('url'), strlen($this->baseUrl));
        if (substr(strtolower($request->query->get('url')), 0, strlen($this->baseUrl)) !== strtolower($this->baseUrl)) {
            throw new Ex\BadRequestHttpException('This is not a valid URL parameter');
        }

        /** handle format parameters */
        $this->params['format'] = $format;
        if (null === $format) {
            $this->params['format'] = $request->query->get('format', 'json');
        }

        if (!in_array($this->params['format'], ['json', 'xml'])) {
            throw new \Exception('Disallowed format parameter \'' . $this->params['format'] . '\'');
        }

        $maxWidth = $request->query->get('maxwidth', null);
        if (is_numeric($maxWidth) || is_null($maxWidth)) {
            $this->params['maxWidth'] = $maxWidth;
        }

        $maxHeight = $request->query->get('maxheight', null);
        if (is_numeric($maxHeight) || is_null($maxHeight)) {
            $this->params['maxHeight'] = $maxHeight;
        }

        $this->params['attr'] = $this->matchRoute($this->params['path']);
    }

    public function matchRoute($path)
    {

        $route1 = new Route('/place-marker/{id}/show', ['controller' => 'PlaceMarkerController']);
        $routes = new RouteCollection();
        $routes->add('place-marker', $route1);

        $context = new RequestContext('/');

        $matcher = new UrlMatcher($routes, $context);

        try {
            return $matcher->match($path);
        } catch (\Exception $ex) {
            throw new Ex\NotFoundHttpException('No implemented!');
        }
    }

    /**
     * @return array
     */
    public function create()
    {
        if (!$this->params) {
            throw new Exception('Unable to create oEmbed. Did you use handleRequest() first?');
        }

        $oEmbed = [
            'version' => '1.0',
            'provider_url' => $this->baseUrl,
            'provider_name' => 'Pixdor.com'
        ];

        switch ($this->params['attr']['_route']) {
            case 'place-marker':

                /**
                 * @var PlaceMarker $pMarker
                 */
                $pMarker = $this->entityManager->getRepository(PlaceMarker::class)->find($this->params['attr']['id']);

                $oEmbed['title'] = $pMarker->getName();
                $oEmbed['url'] = $pMarker->getUrl();
                $oEmbed['description'] = $pMarker->getDescription();
                $oEmbed['caption'] = $pMarker->getCaption();

                $oEmbed['html'] = $this->twig->render(':place_marker:embed.html.twig');
                $oEmbed['width'] = self::HTML_WIDTH;
                $oEmbed['height'] = self::HTML_HEIGHT;

                $oEmbed['rich'] = 'photo';
                break;
        }

        $oEmbed['thumbnail_width'] = isset($this->params['maxWidth']) ? $this->params['maxWidth'] : self::THUMBNAIL_WIDTH;
        $oEmbed['thumbnail_height'] = isset($this->params['thumbnail_height']) ? $this->params['thumbnail_height'] : self::THUMBNAIL_HEIGHT;

        $oEmbed['thumbnail_url'] = sprintf('http://placehold.it/%dx%d', $oEmbed['thumbnail_width'], $oEmbed['thumbnail_height']);

        return $oEmbed;
    }

    /**
     * Returns format type (json|xml)
     * @return string
     */
    public function getFormat()
    {
        if (!$this->params) {
            throw new Exception('Unknown format type. Did you use handleRequest() first?');
        }

        return $this->params['format'];
    }

}

services.yml

app.embed:
    class: AppBundle\Service\EmbedService
    arguments: ["%base_url%", "@doctrine.orm.entity_manager", "@twig"]

parameters.yml

base_url: "http://project.local"

next in the controller:

/**
 * @Route("/oembed.{_format}",
 *     name="embed",
 *     defaults={"_format": null}
 * )
 * @param Request $request
 * @param $_format
 * @return \Symfony\Component\HttpFoundation\Response
 * @throws \Exception
 */
public function generateAction(Request $request, $_format)
{

    $oEmbed = $this->get('app.embed');
    $oEmbed->handleRequest($request, $_format);

    $view = View::create()
        ->setFormat($oEmbed->getFormat())
        ->setStatusCode(200)
        ->setData($oEmbed->create());

    return $this->handleView($view);
}

you call it like this: http://project.local/oembed?url=http://project.local/place-marker/4/show