X-Git-Url: https://git.rapsys.eu/airbundle/blobdiff_plain/c479536facd0d0d7bf97542b060f5ab094855458..28ffa9276b13abd463ef5bf926d8af2f5169d4fb:/Controller/AbstractController.php diff --git a/Controller/AbstractController.php b/Controller/AbstractController.php index 05a928d..73e84f6 100644 --- a/Controller/AbstractController.php +++ b/Controller/AbstractController.php @@ -11,20 +11,30 @@ namespace Rapsys\AirBundle\Controller; +use Doctrine\ORM\EntityManagerInterface; use Doctrine\Persistence\ManagerRegistry; + +use Psr\Container\ContainerInterface; use Psr\Log\LoggerInterface; + use Symfony\Bundle\FrameworkBundle\Controller\AbstractController as BaseAbstractController; -use Symfony\Bundle\FrameworkBundle\Controller\ControllerTrait; +use Symfony\Bundle\SecurityBundle\Security; use Symfony\Component\Asset\PackageInterface; -use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\Filesystem\Exception\IOExceptionInterface; use Symfony\Component\Filesystem\Filesystem; +use Symfony\Component\Form\FormFactoryInterface; +use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\Mailer\MailerInterface; use Symfony\Component\Routing\Generator\UrlGeneratorInterface; use Symfony\Component\Routing\RouterInterface; -use Symfony\Component\Translation\TranslatorInterface; +use Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface; +use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface; use Symfony\Contracts\Service\ServiceSubscriberInterface; +use Symfony\Contracts\Translation\TranslatorInterface; + +use Twig\Environment; use Rapsys\AirBundle\Entity\Dance; use Rapsys\AirBundle\Entity\Location; @@ -32,62 +42,137 @@ use Rapsys\AirBundle\Entity\Slot; use Rapsys\AirBundle\Entity\User; use Rapsys\AirBundle\RapsysAirBundle; +use Rapsys\PackBundle\Util\FacebookUtil; +use Rapsys\PackBundle\Util\ImageUtil; +use Rapsys\PackBundle\Util\MapUtil; +use Rapsys\PackBundle\Util\SluggerUtil; + /** * Provides common features needed in controllers. * * {@inheritdoc} */ abstract class AbstractController extends BaseAbstractController implements ServiceSubscriberInterface { - use ControllerTrait { - //Rename render as baseRender - render as protected baseRender; - } + /** + * Config array + */ + protected array $config; - ///Config array - protected $config; + /** + * Context array + */ + protected array $context; - ///ContainerInterface instance - protected $container; + /** + * Locale string + */ + protected string $locale; - ///Context array - protected $context; + /** + * Modified DateTime + */ + protected \DateTime $modified; + + /** + * DatePeriod instance + */ + protected \DatePeriod $period; - ///Router instance - protected $router; + /** + * Request instance + */ + protected Request $request; - ///Translator instance - protected $translator; + /** + * Route string + */ + protected string $route; /** - * Common constructor - * - * Stores container, router and translator interfaces - * Stores config - * Prepares context tree + * Route params array + */ + protected array $routeParams; + + /** + * Abstract constructor * + * @param AuthorizationCheckerInterface $checker The container instance * @param ContainerInterface $container The container instance + * @param AccessDecisionManagerInterface $decision The decision instance + * @param ManagerRegistry $doctrine The doctrine instance + * @param FacebookUtil $facebook The facebook instance + * @param FormFactoryInterface $factory The factory instance + * @param ImageUtil $image The image instance + * @param MailerInterface $mailer The mailer instance + * @param EntityManagerInterface $manager The manager instance + * @param MapUtil $map The map instance + * @param PackageInterface $package The package instance + * @param RouterInterface $router The router instance + * @param Security $security The security instance + * @param SluggerUtil $slugger The slugger instance + * @param RequestStack $stack The stack instance + * @param TranslatorInterface $translator The translator instance + * @param Environment $twig The twig environment instance + * + * @TODO move all that stuff to setSlugger('@slugger') setters with a calls: [ setSlugger: [ '@slugger' ] ] to unbload classes ??? + * @TODO add a calls: [ ..., prepare: ['@???'] ] that do all the logic that can't be done in constructor because various things are not available */ - public function __construct(ContainerInterface $container) { + public function __construct(protected AuthorizationCheckerInterface $checker, protected ContainerInterface $container, protected AccessDecisionManagerInterface $decision, protected ManagerRegistry $doctrine, protected FacebookUtil $facebook, protected FormFactoryInterface $factory, protected ImageUtil $image, protected MailerInterface $mailer, protected EntityManagerInterface $manager, protected MapUtil $map, protected PackageInterface $package, protected RouterInterface $router, protected Security $security, protected SluggerUtil $slugger, protected RequestStack $stack, protected TranslatorInterface $translator, protected Environment $twig, protected int $limit = 5) { //Retrieve config $this->config = $container->getParameter(RapsysAirBundle::getAlias()); - //Set the container - $this->container = $container; + //Set period + $this->period = new \DatePeriod( + //Start from first monday of week + new \DateTime('Monday this week'), + //Iterate on each day + new \DateInterval('P1D'), + //End with next sunday and 4 weeks + //XXX: we can't use isGranted here as AuthenticatedVoter deny access because user is likely not authenticated yet :'( + new \DateTime('Monday this week + 2 week') + ); + + //Get main request + $this->request = $this->stack->getMainRequest(); + + //Get current locale + $this->locale = $this->request->getLocale(); + + //Set canonical + $canonical = null; + + //Set alternates + $alternates = []; + + //Set route + //TODO: default to not found route ??? + //TODO: pour une url not found, cet attribut n'est pas défini, comment on fait ??? + //XXX: on génère une route bidon par défaut ??? + $this->route = $this->request->attributes->get('_route'); - //Set the router - $this->router = $container->get('router'); + //Set route params + $this->routeParams = $this->request->attributes->get('_route_params'); - //Set the translator - $this->translator = $container->get('translator'); + //With route and routeParams + if ($this->route !== null && $this->routeParams !== null) { + //Set canonical + $canonical = $this->router->generate($this->route, $this->routeParams, UrlGeneratorInterface::ABSOLUTE_URL); + + //Set alternates + $alternates = [ + substr($this->locale, 0, 2) => [ + 'absolute' => $canonical + ] + ]; + } //Set the context $this->context = [ - 'description' => null, - 'section' => null, - 'title' => null, + 'alternates' => $alternates, + 'canonical' => $canonical, 'contact' => [ - 'title' => $this->translator->trans($this->config['contact']['title']), - 'mail' => $this->config['contact']['mail'] + 'address' => $this->config['contact']['address'], + 'name' => $this->translator->trans($this->config['contact']['name']) ], 'copy' => [ 'by' => $this->translator->trans($this->config['copy']['by']), @@ -96,436 +181,70 @@ abstract class AbstractController extends BaseAbstractController implements Serv 'short' => $this->translator->trans($this->config['copy']['short']), 'title' => $this->config['copy']['title'] ], - 'site' => [ - 'donate' => $this->config['site']['donate'], - 'ico' => $this->config['site']['ico'], - 'logo' => $this->config['site']['logo'], - 'png' => $this->config['site']['png'], - 'svg' => $this->config['site']['svg'], - 'title' => $this->translator->trans($this->config['site']['title']), - 'url' => $this->router->generate($this->config['site']['url']) - ], - 'canonical' => null, - 'alternates' => [], + 'description' => null, + 'donate' => $this->config['donate'], 'facebook' => [ - 'prefixes' => [ - 'og' => 'http://ogp.me/ns#', - 'fb' => 'http://ogp.me/ns/fb#' - ], - 'metas' => [ - 'og:type' => 'article', - 'og:site_name' => $this->translator->trans($this->config['site']['title']), - #'fb:admins' => $this->config['facebook']['admins'], - 'fb:app_id' => $this->config['facebook']['apps'] - ], - 'texts' => [] + 'og:type' => 'article', + 'og:site_name' => $title = $this->translator->trans($this->config['title']), + 'og:url' => $canonical, + #'fb:admins' => $this->config['facebook']['admins'], + 'fb:app_id' => $this->config['facebook']['apps'] + ], + //XXX: TODO: only generate it when fb robot request the url ??? + 'fbimage' => [ + 'texts' => [ + $title => [ + 'font' => 'irishgrover', + 'size' => 110 + ] + ] ], - 'forms' => [] + 'icon' => $this->config['icon'], + 'keywords' => null, + 'locale' => str_replace('_', '-', $this->locale), + 'logo' => $this->config['logo'], + 'forms' => [], + 'root' => $this->router->generate($this->config['root']), + 'title' => [ + 'page' => null, + 'section' => null, + 'site' => $title + ] ]; } - /** - * Return the facebook image - * - * @desc Generate image in jpeg format or load it from cache - * - * @param string $pathInfo The request path info - * @param array $parameters The image parameters - * @return array The image array - */ - protected function getFacebookImage(string $pathInfo, array $parameters = []): array { - //Get asset package - //XXX: require asset package to be public - $package = $this->container->get('rapsys_pack.path_package'); - - //Set texts - $texts = $parameters['texts'] ?? []; - - //Set default source - $source = $parameters['source'] ?? 'png/facebook.png'; - - //Set default source - $updated = $parameters['updated'] ?? strtotime('last week'); - - //Set source path - $src = $this->config['path']['public'].'/'.$source; - - //Set cache path - //XXX: remove extension and store as png anyway - $cache = $this->config['path']['cache'].'/facebook/'.substr($source, 0, strrpos($source, '.')).'.'.$this->config['facebook']['width'].'x'.$this->config['facebook']['height'].'.png'; - - //Set destination path - //XXX: format /facebook.jpeg - //XXX: was /facebook//..jpeg - $dest = $this->config['path']['public'].'/facebook'.$pathInfo.'.jpeg'; - - //With up to date generated image - if ( - is_file($dest) && - ($stat = stat($dest)) && - $stat['mtime'] >= $updated - ) { - //Get image size - list ($width, $height) = getimagesize($dest); - - //Iterate each text - foreach($texts as $text => $data) { - //With canonical text - if (!empty($data['canonical'])) { - //Prevent canonical to finish in alt - unset($texts[$text]); - } - } - - //Return image data - return [ - 'og:image' => $package->getAbsoluteUrl('@RapsysAir/facebook/'.$stat['mtime'].$pathInfo.'.jpeg'), - 'og:image:alt' => str_replace("\n", ' ', implode(' - ', array_keys($texts))), - 'og:image:height' => $height, - 'og:image:width' => $width - ]; - //With image candidate - } elseif (is_file($src)) { - //Create image object - $image = new \Imagick(); - - //With cache image - if (is_file($cache)) { - //Read image - $image->readImage($cache); - //Without we generate it - } else { - //Check target directory - if (!is_dir($dir = dirname($cache))) { - //Create filesystem object - $filesystem = new Filesystem(); - - try { - //Create dir - //XXX: set as 0775, symfony umask (0022) will reduce rights (0755) - $filesystem->mkdir($dir, 0775); - } catch (IOExceptionInterface $e) { - //Throw error - throw new \Exception(sprintf('Output directory "%s" do not exists and unable to create it', $dir), 0, $e); - } - } - - //Read image - $image->readImage($src); - - //Crop using aspect ratio - //XXX: for better result upload image directly in aspect ratio :) - $image->cropThumbnailImage($this->config['facebook']['width'], $this->config['facebook']['height']); - - //Strip image exif data and properties - $image->stripImage(); - - //Save cache image - if (!$image->writeImage($cache)) { - //Throw error - throw new \Exception(sprintf('Unable to write image "%s"', $cache)); - } - } - //Check target directory - if (!is_dir($dir = dirname($dest))) { - //Create filesystem object - $filesystem = new Filesystem(); - - try { - //Create dir - //XXX: set as 0775, symfony umask (0022) will reduce rights (0755) - $filesystem->mkdir($dir, 0775); - } catch (IOExceptionInterface $e) { - //Throw error - throw new \Exception(sprintf('Output directory "%s" do not exists and unable to create it', $dir), 0, $e); - } - } - - //Get image width - $width = $image->getImageWidth(); - - //Get image height - $height = $image->getImageHeight(); - - //Create draw - $draw = new \ImagickDraw(); - - //Set stroke antialias - $draw->setStrokeAntialias(true); - - //Set text antialias - $draw->setTextAntialias(true); - - //Set font aliases - $fonts = [ - 'irishgrover' => $this->config['path']['public'].'/ttf/irishgrover.v10.ttf', - 'droidsans' => $this->config['path']['public'].'/ttf/droidsans.regular.ttf', - 'dejavusans' => $this->config['path']['public'].'/ttf/dejavusans.2.37.ttf', - 'labelleaurore' => $this->config['path']['public'].'/ttf/labelleaurore.v10.ttf' - ]; - - //Set align aliases - $aligns = [ - 'left' => \Imagick::ALIGN_LEFT, - 'center' => \Imagick::ALIGN_CENTER, - 'right' => \Imagick::ALIGN_RIGHT - ]; - - //Set default font - $defaultFont = 'dejavusans'; - - //Set default align - $defaultAlign = 'center'; - - //Set default size - $defaultSize = 60; - - //Set default stroke - $defaultStroke = '#00c3f9'; - - //Set default width - $defaultWidth = 15; - - //Set default fill - $defaultFill = 'white'; - - //Init counter - $i = 1; - - //Set text count - $count = count($texts); - - //Draw each text stroke - foreach($texts as $text => $data) { - //Set font - $draw->setFont($fonts[$data['font']??$defaultFont]); - - //Set font size - $draw->setFontSize($data['size']??$defaultSize); - - //Set stroke width - $draw->setStrokeWidth($data['width']??$defaultWidth); - - //Set text alignment - $draw->setTextAlignment($align = ($aligns[$data['align']??$defaultAlign])); - - //Get font metrics - $metrics = $image->queryFontMetrics($draw, $text); - - //Without y - if (empty($data['y'])) { - //Position verticaly each text evenly - $texts[$text]['y'] = $data['y'] = (($height + 100) / (count($texts) + 1) * $i) - 50; - } - - //Without x - if (empty($data['x'])) { - if ($align == \Imagick::ALIGN_CENTER) { - $texts[$text]['x'] = $data['x'] = $width/2; - } elseif ($align == \Imagick::ALIGN_LEFT) { - $texts[$text]['x'] = $data['x'] = 50; - } elseif ($align == \Imagick::ALIGN_RIGHT) { - $texts[$text]['x'] = $data['x'] = $width - 50; - } - } - - //Center verticaly - //XXX: add ascender part then center it back by half of textHeight - //TODO: maybe add a boundingbox ??? - $texts[$text]['y'] = $data['y'] += $metrics['ascender'] - $metrics['textHeight']/2; - - //Set stroke color - $draw->setStrokeColor(new \ImagickPixel($data['stroke']??$defaultStroke)); - - //Set fill color - $draw->setFillColor(new \ImagickPixel($data['stroke']??$defaultStroke)); - - //Add annotation - $draw->annotation($data['x'], $data['y'], $text); - - //Increase counter - $i++; - } - - //Create stroke object - $stroke = new \Imagick(); - - //Add new image - $stroke->newImage($width, $height, new \ImagickPixel('transparent')); - - //Draw on image - $stroke->drawImage($draw); - - //Blur image - //XXX: blur the stroke canvas only - $stroke->blurImage(5,3); - - //Set opacity to 0.5 - //XXX: see https://www.php.net/manual/en/image.evaluateimage.php - $stroke->evaluateImage(\Imagick::EVALUATE_DIVIDE, 1.5, \Imagick::CHANNEL_ALPHA); - - //Compose image - $image->compositeImage($stroke, \Imagick::COMPOSITE_OVER, 0, 0); - - //Clear stroke - $stroke->clear(); - - //Destroy stroke - unset($stroke); - - //Clear draw - $draw->clear(); - - //Set text antialias - $draw->setTextAntialias(true); - - //Draw each text - foreach($texts as $text => $data) { - //Set font - $draw->setFont($fonts[$data['font']??$defaultFont]); - - //Set font size - $draw->setFontSize($data['size']??$defaultSize); - - //Set text alignment - $draw->setTextAlignment($aligns[$data['align']??$defaultAlign]); - - //Set fill color - $draw->setFillColor(new \ImagickPixel($data['fill']??$defaultFill)); - - //Add annotation - $draw->annotation($data['x'], $data['y'], $text); - - //With canonical text - if (!empty($data['canonical'])) { - //Prevent canonical to finish in alt - unset($texts[$text]); - } - } - - //Draw on image - $image->drawImage($draw); - - //Strip image exif data and properties - $image->stripImage(); - - //Set image format - $image->setImageFormat('jpeg'); - - //Save image - if (!$image->writeImage($dest)) { - //Throw error - throw new \Exception(sprintf('Unable to write image "%s"', $dest)); - } - - //Get dest stat - $stat = stat($dest); - - //Return image data - return [ - 'og:image' => $package->getAbsoluteUrl('@RapsysAir/facebook/'.$stat['mtime'].$pathInfo.'.jpeg'), - 'og:image:alt' => str_replace("\n", ' ', implode(' - ', array_keys($texts))), - 'og:image:height' => $height, - 'og:image:width' => $width - ]; - } - - //Return empty array without image - return []; - } - /** * Renders a view * * {@inheritdoc} */ protected function render(string $view, array $parameters = [], Response $response = null): Response { - //Get request stack - $stack = $this->container->get('request_stack'); - - //Get current request - $request = $stack->getCurrentRequest(); - - //Get current locale - $locale = $request->getLocale(); - - //Set locale - $parameters['locale'] = str_replace('_', '-', $locale); - - //Get context path - $pathInfo = $this->router->getContext()->getPathInfo(); - - //Iterate on locales excluding current one - foreach($this->config['locales'] as $current) { - //Set titles - $titles = []; - - //Iterate on other locales - foreach(array_diff($this->config['locales'], [$current]) as $other) { - $titles[$other] = $this->translator->trans($this->config['languages'][$current], [], null, $other); - } - - //Retrieve route matching path - $route = $this->router->match($pathInfo); - - //Get route name - $name = $route['_route']; - - //Unset route name - unset($route['_route']); - - //With current locale - if ($current == $locale) { - //Set locale locales context - $parameters['canonical'] = $this->router->generate($name, ['_locale' => $current]+$route, UrlGeneratorInterface::ABSOLUTE_URL); - } else { - //Set locale locales context - $parameters['alternates'][str_replace('_', '-', $current)] = [ - 'absolute' => $this->router->generate($name, ['_locale' => $current]+$route, UrlGeneratorInterface::ABSOLUTE_URL), - 'relative' => $this->router->generate($name, ['_locale' => $current]+$route), - 'title' => implode('/', $titles), - 'translated' => $this->translator->trans($this->config['languages'][$current], [], null, $current) - ]; - } - - //Add shorter locale - if (empty($parameters['alternates'][$shortCurrent = substr($current, 0, 2)])) { - //Set locale locales context - $parameters['alternates'][$shortCurrent] = [ - 'absolute' => $this->router->generate($name, ['_locale' => $current]+$route, UrlGeneratorInterface::ABSOLUTE_URL), - 'relative' => $this->router->generate($name, ['_locale' => $current]+$route), - 'title' => implode('/', $titles), - 'translated' => $this->translator->trans($this->config['languages'][$current], [], null, $current) - ]; - } - } + //Create response when null + $response ??= new Response(); //Create application form for role_guest - if ($this->isGranted('ROLE_GUEST')) { + if ($this->checker->isGranted('ROLE_GUEST')) { //Without application form if (empty($parameters['forms']['application'])) { - //Fetch doctrine - $doctrine = $this->get('doctrine'); - //Get favorites dances - $danceFavorites = $doctrine->getRepository(Dance::class)->findByUserId($this->getUser()->getId()); + $danceFavorites = $this->doctrine->getRepository(Dance::class)->findByUserId($this->security->getUser()->getId()); //Set dance default $danceDefault = !empty($danceFavorites)?current($danceFavorites):null; //Get favorites locations - $locationFavorites = $doctrine->getRepository(Location::class)->findByUserId($this->getUser()->getId()); + $locationFavorites = $this->doctrine->getRepository(Location::class)->findByUserId($this->security->getUser()->getId()); //Set location default $locationDefault = !empty($locationFavorites)?current($locationFavorites):null; //With admin - if ($this->isGranted('ROLE_ADMIN')) { + if ($this->checker->isGranted('ROLE_ADMIN')) { //Get dances - $dances = $doctrine->getRepository(Dance::class)->findAll(); + $dances = $this->doctrine->getRepository(Dance::class)->findAll(); //Get locations - $locations = $doctrine->getRepository(Location::class)->findAll(); + $locations = $this->doctrine->getRepository(Location::class)->findAll(); //Without admin } else { //Restrict to favorite dances @@ -541,8 +260,24 @@ abstract class AbstractController extends BaseAbstractController implements Serv $locationFavorites = []; } + //With session application dance id + if (!empty($parameters['session']['application']['dance']['id'])) { + //Iterate on each dance + foreach($dances as $dance) { + //Found dance + if ($dance->getId() == $parameters['session']['application']['dance']['id']) { + //Set dance as default + $danceDefault = $dance; + + //Stop search + break; + } + } + } + //With session location id //XXX: set in session controller + //TODO: with new findAll that key by id, it should be as simple as isset($locations[$id]) ? if (!empty($parameters['session']['location']['id'])) { //Iterate on each location foreach($locations as $location) { @@ -558,9 +293,9 @@ abstract class AbstractController extends BaseAbstractController implements Serv } //Create ApplicationType form - $application = $this->createForm('Rapsys\AirBundle\Form\ApplicationType', null, [ + $application = $this->factory->create('Rapsys\AirBundle\Form\ApplicationType', null, [ //Set the action - 'action' => $this->generateUrl('rapsys_air_application_add'), + 'action' => $this->generateUrl('rapsysair_application_add'), //Set the form attribute 'attr' => [ 'class' => 'col' ], //Set dance choices @@ -576,25 +311,28 @@ abstract class AbstractController extends BaseAbstractController implements Serv //Set location favorites 'location_favorites' => $locationFavorites, //With user - 'user' => $this->isGranted('ROLE_ADMIN'), + 'user' => $this->checker->isGranted('ROLE_ADMIN'), //Set user choices - 'user_choices' => $doctrine->getRepository(User::class)->findAllWithTranslatedGroupAndCivility($this->translator), + 'user_choices' => $this->doctrine->getRepository(User::class)->findChoicesAsArray(), //Set default user to current - 'user_default' => $this->getUser()->getId(), + 'user_default' => $this->security->getUser()->getId(), //Set to session slot or evening by default //XXX: default to Evening (3) - 'slot_default' => $doctrine->getRepository(Slot::class)->findOneById($parameters['session']['slot']['id']??3) + 'slot_default' => $this->doctrine->getRepository(Slot::class)->findOneById($parameters['session']['slot']['id']??3) ]); //Add form to context $parameters['forms']['application'] = $application->createView(); } + }/* + #XXX: removed because it fucks up the seo by displaying register and login form instead of content + #XXX: until we find a better way, removed !!! //Create login form for anonymous - } elseif (!$this->isGranted('IS_AUTHENTICATED_REMEMBERED')) { + elseif (!$this->checker->isGranted('IS_AUTHENTICATED_REMEMBERED')) { //Create LoginType form - $login = $this->createForm('Rapsys\UserBundle\Form\LoginType', null, [ + $login = $this->factory->create('Rapsys\UserBundle\Form\LoginType', null, [ //Set the action - 'action' => $this->generateUrl('rapsys_user_login'), + 'action' => $this->generateUrl('rapsysuser_login'), //Disable password repeated 'password_repeated' => false, //Set the form attribute @@ -624,18 +362,15 @@ abstract class AbstractController extends BaseAbstractController implements Serv 'phone' => false ]; - //Get slugger - $slugger = $this->container->get('rapsys_pack.slugger_util'); - //Create RegisterType form - $register = $this->createForm('Rapsys\AirBundle\Form\RegisterType', null, $field+[ + $register = $this->factory->create('Rapsys\AirBundle\Form\RegisterType', null, $field+[ //Set the action 'action' => $this->generateUrl( - 'rapsys_user_register', + 'rapsysuser_register', [ - 'mail' => $smail = $slugger->short(''), - 'field' => $sfield = $slugger->serialize($field), - 'hash' => $slugger->hash($smail.$sfield) + 'mail' => $smail = $this->slugger->short(''), + 'field' => $sfield = $this->slugger->serialize($field), + 'hash' => $this->slugger->hash($smail.$sfield) ] ), //Set the form attribute @@ -644,50 +379,110 @@ abstract class AbstractController extends BaseAbstractController implements Serv //Add form to context $parameters['forms']['register'] = $register->createView(); + }*/ + + //Without alternates + if (count($parameters['alternates']) <= 1) { + //Set routeParams + $routeParams = $this->routeParams; + + //Iterate on locales excluding current one + foreach($this->config['locales'] as $locale) { + //With current locale + if ($locale !== $this->locale) { + //Set titles + $titles = []; + + //Set route params locale + $routeParams['_locale'] = $locale; + + //Iterate on other locales + foreach(array_diff($this->config['locales'], [$locale]) as $other) { + //Set other locale title + $titles[$other] = $this->translator->trans($this->config['languages'][$locale], [], null, $other); + } + + //Set locale locales context + $parameters['alternates'][str_replace('_', '-', $locale)] = [ + 'absolute' => $this->router->generate($this->route, $routeParams, UrlGeneratorInterface::ABSOLUTE_URL), + 'relative' => $this->router->generate($this->route, $routeParams), + 'title' => implode('/', $titles), + 'translated' => $this->translator->trans($this->config['languages'][$locale], [], null, $locale) + ]; + + //Add shorter locale + if (empty($parameters['alternates'][$shortCurrent = substr($locale, 0, 2)])) { + //Set locale locales context + $parameters['alternates'][$shortCurrent] = $parameters['alternates'][str_replace('_', '-', $locale)]; + } + } + } } //With page infos and without facebook texts - if (empty($parameters['facebook']['texts']) && !empty($parameters['site']['title']) && !empty($parameters['title']) && !empty($parameters['canonical'])) { - //Set facebook image - $parameters['facebook']['texts'] = [ - $parameters['site']['title'] => [ - 'font' => 'irishgrover', - 'size' => 110 - ], - $parameters['title'] => [ - 'align' => 'left' - ], - $parameters['canonical'] => [ + if (count($parameters['fbimage']) <= 1 && isset($parameters['title']) && isset($this->route) && isset($this->routeParams)) { + //Append facebook image texts + $parameters['fbimage'] += [ + 'texts' => [ + $parameters['title']['page'] => [ + 'font' => 'irishgrover', + 'align' => 'left' + ]/*XXX: same problem as url, too long :'(, + $parameters['description'] => [ + 'align' => 'right', + 'canonical' => true, + 'font' => 'labelleaurore', + 'size' => 50 + ]*/ + ] + ]; + + /*With short path info + We don't add this stupid url in image !!! + if (strlen($pathInfo = $this->router->generate($this->route, $this->routeParams)) <= 64) { + => [ 'align' => 'right', 'canonical' => true, 'font' => 'labelleaurore', 'size' => 50 - ] - ]; + ] + }*/ + } + + //With empty locations link + if (empty($parameters['locations_link'])) { + //Set locations link + $parameters['locations_link'] = $this->router->generate('rapsysair_location'); + } + + //With empty locations title + if (empty($parameters['locations_title'])) { + //Set locations title + $parameters['locations_title'] = $this->translator->trans('Locations', [], null, $this->locale); } //With canonical if (!empty($parameters['canonical'])) { //Set facebook url - $parameters['facebook']['metas']['og:url'] = $parameters['canonical']; + $parameters['facebook']['og:url'] = $parameters['canonical']; } //With empty facebook title and title - if (empty($parameters['facebook']['metas']['og:title']) && !empty($parameters['title'])) { + if (empty($parameters['facebook']['og:title']) && !empty($parameters['title'])) { //Set facebook title - $parameters['facebook']['metas']['og:title'] = $parameters['title']; + $parameters['facebook']['og:title'] = $parameters['title']; } //With empty facebook description and description - if (empty($parameters['facebook']['metas']['og:description']) && !empty($parameters['description'])) { + if (empty($parameters['facebook']['og:description']) && !empty($parameters['description'])) { //Set facebook description - $parameters['facebook']['metas']['og:description'] = $parameters['description']; + $parameters['facebook']['og:description'] = $parameters['description']; } //With locale - if (!empty($locale)) { + if (!empty($this->locale)) { //Set facebook locale - $parameters['facebook']['metas']['og:locale'] = $locale; + $parameters['facebook']['og:locale'] = $this->locale; //With alternates //XXX: locale change when fb_locale=xx_xx is provided is done in FacebookSubscriber @@ -697,20 +492,36 @@ abstract class AbstractController extends BaseAbstractController implements Serv foreach($parameters['alternates'] as $lang => $alternate) { if (strlen($lang) == 5) { //Set facebook locale alternate - $parameters['facebook']['metas']['og:locale:alternate'] = str_replace('-', '_', $lang); + $parameters['facebook']['og:locale:alternate'] = str_replace('-', '_', $lang); } } } } //Without facebook image defined and texts - if (empty($parameters['facebook']['metas']['og:image']) && !empty($parameters['facebook']['texts'])) { + if (empty($parameters['facebook']['og:image']) && !empty($this->request) && !empty($parameters['fbimage']['texts']) && !empty($this->modified)) { //Get facebook image - $parameters['facebook']['metas'] += $this->getFacebookImage($pathInfo, $parameters['facebook']); + $parameters['facebook'] += $this->facebook->getImage($this->request->getPathInfo(), $parameters['fbimage']['texts'], $this->modified->getTimestamp()); + } + + //Call twig render method + $content = $this->twig->render($view, $parameters); + + //Invalidate OK response on invalid form + if (200 === $response->getStatusCode()) { + foreach ($parameters as $v) { + if ($v instanceof FormInterface && $v->isSubmitted() && !$v->isValid()) { + $response->setStatusCode(422); + break; + } + } } - //Call parent method - return $this->baseRender($view, $parameters, $response); + //Store content in response + $response->setContent($content); + + //Return response + return $response; } /** @@ -721,11 +532,20 @@ abstract class AbstractController extends BaseAbstractController implements Serv public static function getSubscribedServices(): array { //Return subscribed services return [ - //'logger' => LoggerInterface::class, 'doctrine' => ManagerRegistry::class, - 'rapsys_pack.path_package' => PackageInterface::class, + 'doctrine.orm.default_entity_manager' => EntityManagerInterface::class, + 'form.factory' => FormFactoryInterface::class, + 'mailer.mailer' => MailerInterface::class, + 'rapsysair.facebook_util' => FacebookUtil::class, + 'rapsyspack.image_util' => ImageUtil::class, + 'rapsyspack.map_util' => MapUtil::class, + 'rapsyspack.path_package' => PackageInterface::class, + 'rapsyspack.slugger_util' => SluggerUtil::class, + 'rapsysuser.access_decision_manager' => AccessDecisionManagerInterface::class, 'request_stack' => RequestStack::class, 'router' => RouterInterface::class, + 'security.authorization_checker' => AuthorizationCheckerInterface::class, + 'service_container' => ContainerInterface::class, 'translator' => TranslatorInterface::class ]; }