eZ Platform Discussions

Too simple RSS script


#1

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:


#2

To access the feed url!


#3

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.