Ibexa DXP Discussions

Community discussion forum for developers working with Ibexa DXP

Too simple RSS script

Good morning, everyone.

It seems that RSS is back in fashion…
Whether it’s true or not, I was asked to put one in place.

It is very simple: The X most recent Article/Breve under the content.tree_root.location_id of the siteaccess.

After a very (too) fast search, I didn’t find a symfony bundle that only makes this gift I need.
And as my need is very simple I launched myself.

So here’s my RSS feed generation script if it helps anyone…

src/MyBundle/Command/DumpRss2Command.php

<?php

namespace MyBundle\Command;

use eZ\Publish\API\Repository\Values\Content\Location;
use eZ\Publish\API\Repository\Values\Content\LocationQuery;
use eZ\Publish\API\Repository\Values\Content\Query;
use eZ\Publish\Core\MVC\Symfony\Routing\ChainRouter;
use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use eZ\Publish\Core\MVC\Symfony\SiteAccess;
use Symfony\Component\HttpFoundation\Request;

class DumpRss2Command extends ContainerAwareCommand
{

    protected function configure()
    {
        $this
            ->setName('my:cron:dump-rss2')
            ->setDescription('')
        ;
    }

    protected function getRepository()
    {
        return $this->getContainer()->get('ezpublish.api.repository');
    }

    protected function execute(InputInterface $input, OutputInterface $output)
    {
        /** @var \Symfony\Bridge\Monolog\Logger $logger */
        $logger = $this->getContainer()->get('monolog.logger.dump-rss2');

        $logger->notice("Start ".$this->getName(). ' ' . date('c'));

        // Siteaccess REQUIRED.
        $siteaccess = $input->getOption('siteaccess');
        if (!$siteaccess) {
            $msg = "siteaccess option Required";
            $logger->critical($msg);
            throw new \Exception($msg);
        }
        $logger->notice('Siteaccess: '.$siteaccess);

        // get services
        $searchService = $this->getRepository()->getSearchService();
        $locationService = $this->getRepository()->getLocationService();
        /** @var \eZ\Bundle\EzPublishCoreBundle\DependencyInjection\Configuration\ChainConfigResolver */
        $configResolver = $this->getContainer()->get('ezpublish.config.resolver');
        /** @var ChainRouter $router */
        $router = $this->getContainer()->get( 'router' );
        /** @var \eZ\Publish\Core\MVC\Symfony\Routing\Generator\RouteReferenceGenerator $routeRefGenerator */
        $routeRefGenerator = $this->getContainer()->get('ezpublish.route_reference.generator');

        // Prépare URL Générator
        $requestStack = new RequestStack();
        $requestStack->push(new Request());
        $routeRefGenerator->setRequestStack($requestStack);
        $this->getContainer()->get('ezpublish.siteaccess_router')->setSiteAccess(new SiteAccess($siteaccess));


        // get Root Location
        $rootLocationId = $configResolver->getParameter('content.tree_root.location_id');
        if (!$rootLocationId) {
            $msg = "Parameter 'content.tree_root.location_id' appears to be configured incorrectly";
            $logger->critical($msg);
            throw new \Exception($msg);
        }
        $logger->debug('$rootLocationId='.$rootLocationId);
        //$output->writeln($rootLocationId);
        $rootLocation = $locationService->loadLocation($rootLocationId);


        // Paramètres
        $limit = 25;
        $contentTypeIdentifiers = ['breve', 'article'];
        $subtrees = [$rootLocation->pathString];
        $file = "web/var/site/storage/public/$siteaccess.rss";
        $length = 250;

        $logger->debug("Parameters:" , [
            '$limit' => $limit,
            '$contentTypeIdentifiers' => $contentTypeIdentifiers,
            '$subtrees' => $subtrees,
            '$file' => $file,
            '$length' => $length,
        ]);

        $path_prefix = '';

        if (getcwd() === '/var/www/html' && is_dir('/var/www/html/project/ezplatform')) {
            $path_prefix = './project/ezplatform/';
            $logger->warning("Le current directory n'est pas la racine du ezplatform. Cela se produit lorsque la commande est lancé via docker...", [
                'getcwd' => getcwd(),
                '__METHOD__' => __METHOD__,
                '$path_prefix' => $path_prefix,
            ]);
        }

        // Check dir.
        $dir = dirname($path_prefix.$file);
        if (!is_dir($dir)) {
            mkdir($dir, 0777, true);
            if (!is_dir($dir)) {
                $msg = "Cannot create folder '$dir'";
                $logger->critical($msg);
                throw new \Exception($msg);
            }
        }

        // Get Locations
        $locationQuery = new LocationQuery();
        $locationQuery->filter = new Query\Criterion\LogicalAnd([
            new Query\Criterion\ContentTypeIdentifier($contentTypeIdentifiers),
            new Query\Criterion\Visibility(Query\Criterion\Visibility::VISIBLE), // Normalement inutile ...
            new Query\Criterion\Subtree($subtrees),

        ]);
        $locationQuery->limit = $limit;
        $locationQuery->sortClauses = [
            new Query\SortClause\DatePublished(Query::SORT_DESC), // TODO Trie par field : publich_date + DatePublished
        ];
        $searchResult = $searchService->findLocations($locationQuery);
        $searchHits = $searchResult->searchHits;
        $TT = count($searchHits);

        $logger->notice($TT.' item found');

        // XML by item
        $xml_items = '';
        foreach ($searchHits as $i => $hit) {
            $ii = str_pad(++$i, strlen("$TT"));
            /** @var Location $location */
            $location = $hit->valueObject;
            $logger->info("[$ii/$TT] L:".$location->id.' '.$location->contentInfo->name);

            /** @var \eZ\Publish\Core\FieldType\RichText\Value $f */
            $f = $location->getContent()->getFieldValue('accroche');
            $description = '';
            if ($f instanceof \eZ\Publish\Core\FieldType\RichText\Value) {
                $description = substr($f->xml->textContent, 0, $length);
            } elseif ($f instanceof \eZ\Publish\Core\FieldType\TextBlock\Value) {
                $description = substr($f->text, 0, $length);
            }
            $pubDate = $location->contentInfo->publishedDate->format('c');

            /** @var \eZ\Publish\Core\MVC\Symfony\Routing\RouteReference $routeReference */
            $routeReference = $routeRefGenerator->generate($location);
            $routeReference->set('siteaccess', $siteaccess);
            $link = $router->generate($routeReference, [], UrlGeneratorInterface::ABSOLUTE_URL);

            $xml_items .= "
                <item>
                    <title>{$location->contentInfo->name}</title>
                    <description>{$description}</description>
                    <pubDate>{$pubDate}</pubDate>
                    <link>{$link}</link>
                </item>";
        }

        // Root URL
        /** @var \eZ\Publish\Core\MVC\Symfony\Routing\RouteReference $routeReference */
        $routeReference = $routeRefGenerator->generate($rootLocation);
        $routeReference->set('siteaccess', $siteaccess);
        $link = $router->generate($routeReference, [], UrlGeneratorInterface::ABSOLUTE_URL);

        // XML
        $xml = '<?xml version="1.0" encoding="UTF-8"?>'.PHP_EOL;
        $xml .= '<rss version="2.0">'.PHP_EOL;
        $xml .= '<channel>'.PHP_EOL;
        $xml .= '<title>'.$rootLocation->contentInfo->name.'</title>'.PHP_EOL;
        $xml .= '<generator>'.$this->getName().'</generator>'.PHP_EOL;
        $xml .= '<description>'.$siteaccess.'</description>'.PHP_EOL;
        $xml .= '<lastBuildDate>'.date('c').'</lastBuildDate>'.PHP_EOL;
        $xml .= '<link>'.$link.'</link>'.PHP_EOL;
        $xml .= $xml_items.PHP_EOL;
        $xml .= '</channel>';

        $logger->debug($xml);


        $file_put_contents = file_put_contents($path_prefix.$file, $xml);

        if (!$file_put_contents) {
            $msg = "Cannot create file '$path_prefix$file'";
            $logger->critical($msg);
            throw new \Exception($msg);
        }

        $output->writeln('END');
    }

    /*
<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
    <channel>
        <title>Mon site</title>
        <description>Ceci est un exemple de flux RSS 2.0</description>
        <lastBuildDate>Sat, 07 Sep 2002 00:00:01 GMT</lastBuildDate>
        <link>http://www.example.org</link>
        <item>
            <title>Actualité N°1</title>
            <description>Ceci est ma première actualité</description>
            <pubDate>Sat, 07 Sep 2002 00:00:01 GMT</pubDate>
            <link>http://www.example.org/actu1</link>
        </item>
        <item>
            <title>Actualité N°2</title>
            <description>Ceci est ma seconde actualité</description>
            <pubDate>Sat, 07 Sep 2002 00:00:01 GMT</pubDate>
            <link>http://www.example.org/actu2</link>
        </item>
    </channel>
</rss>
     */
}

If it helps anyone :slight_smile:

Or better yet! Opening the debate on how to do it right :smiley:

4 Likes

To access the feed url!

1 Like

Thanks for sharing this @remy_php ! Will your Bundle be added to Packagist? If so, we could also add it to https://ezplatform.com/Bundles.