Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Zend feed refactoring #9347

Merged
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
ca9e582
Zend_Feed refactoring progress
ldusan84 Apr 20, 2017
ed33b18
Tests refactoring
ldusan84 Apr 21, 2017
c7ba65a
Fixed unit test
ldusan84 Apr 22, 2017
9d0a290
Tidying up files
ldusan84 Apr 22, 2017
109047f
Small CS fix
ldusan84 Apr 22, 2017
4534a2e
Small CS fix
ldusan84 Apr 22, 2017
c413389
More CS fixes
ldusan84 Apr 29, 2017
caa4471
Small exception fix
ldusan84 May 7, 2017
66154e6
Changes after the code review
ldusan84 May 24, 2017
49bcf98
Zend Feed refactorging WIP
ldusan84 Jul 27, 2017
c0b4c7a
Implementing code review requested changes
ldusan84 Aug 7, 2017
411d0fc
Merge branch 'develop' into feature/zend_feed_refactoring
Aug 30, 2017
9779ebe
Zend Feed refactoring WIP
ldusan84 Sep 4, 2017
eba92d0
magento/magento2#9347: Merge branch 'develop' of github.com:magento/m…
ishakhsuvarov Sep 13, 2017
983d74f
magento/magento2#9347: Zend feed refactoring
ishakhsuvarov Sep 13, 2017
0b51e8c
magento/magento2#9347: Zend feed refactoring
ishakhsuvarov Sep 13, 2017
74d431a
magento/magento2#9347: Zend feed refactoring
ishakhsuvarov Sep 13, 2017
7f73d67
Zend Feed refactoring WIP
ldusan84 Sep 25, 2017
2933223
Zend Feed refactoring WIP
ldusan84 Sep 25, 2017
64610d3
Removed the wrong lines commited
ldusan84 Sep 25, 2017
d2d397a
Fixing stuff as requested
ldusan84 Nov 16, 2017
0770227
Some code style fixes
ldusan84 Nov 23, 2017
735c840
RSS model fix
ldusan84 Nov 23, 2017
7e17d20
Unit test fix
ldusan84 Nov 24, 2017
46c51ba
RSS model fix
ldusan84 Nov 24, 2017
3a3683f
Code style fixes
ldusan84 Dec 22, 2017
6311d5c
Code fixes
ldusan84 Dec 22, 2017
4462eaf
Added some missing properties and renamed stuff
ldusan84 Dec 22, 2017
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 12 additions & 3 deletions app/code/Magento/Rss/Model/Rss.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use Magento\Framework\App\ObjectManager;
use Magento\Framework\App\Rss\DataProviderInterface;
use Magento\Framework\Serialize\SerializerInterface;
use Magento\Framework\App\FeedImporterInterface;

class Rss
{
Expand All @@ -21,6 +22,11 @@ class Rss
*/
protected $cache;

/**
* @var \Magento\Framework\App\FeedImporterInterface
*/
private $feedImporter;

/**
* @var SerializerInterface
*/
Expand All @@ -31,13 +37,16 @@ class Rss
*
* @param \Magento\Framework\App\CacheInterface $cache
* @param SerializerInterface|null $serializer
* @param FeedImporterInterface|null $feedImporter
*/
public function __construct(
\Magento\Framework\App\CacheInterface $cache,
SerializerInterface $serializer = null
SerializerInterface $serializer = null,
FeedImporterInterface $feedImporter = null
) {
$this->cache = $cache;
$this->serializer = $serializer ?: ObjectManager::getInstance()->get(SerializerInterface::class);
$this->feedImporter = $feedImporter ?: ObjectManager::getInstance()->get(FeedImporterInterface::class);
}

/**
Expand Down Expand Up @@ -86,7 +95,7 @@ public function setDataProvider(DataProviderInterface $dataProvider)
*/
public function createRssXml()
{
$rssFeedFromArray = \Zend_Feed::importArray($this->getFeeds(), 'rss');
return $rssFeedFromArray->saveXML();
$rssFeed = $this->feedImporter->importArray($this->getFeeds(), 'rss');
return $rssFeed->asXML();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -103,14 +103,22 @@ public function testExecuteWithException()
$dataProvider = $this->getMock(\Magento\Framework\App\Rss\DataProviderInterface::class);
$dataProvider->expects($this->once())->method('isAllowed')->will($this->returnValue(true));

$rssModel = $this->getMock(\Magento\Rss\Model\Rss::class, ['setDataProvider'], [], '', false);
$rssModel = $this->getMock(\Magento\Rss\Model\Rss::class, ['setDataProvider', 'createRssXml'], [], '', false);
$rssModel->expects($this->once())->method('setDataProvider')->will($this->returnSelf());

$exceptionMock = new \Magento\Framework\Exception\RuntimeException(
new \Magento\Framework\Phrase('Any message')
);

$rssModel->expects($this->once())->method('createRssXml')->will(
$this->throwException($exceptionMock)
);

$this->response->expects($this->once())->method('setHeader')->will($this->returnSelf());
$this->rssFactory->expects($this->once())->method('create')->will($this->returnValue($rssModel));
$this->rssManager->expects($this->once())->method('getProvider')->will($this->returnValue($dataProvider));

$this->setExpectedException('\Zend_Feed_Builder_Exception');
$this->setExpectedException(\Magento\Framework\Exception\RuntimeException::class);
$this->controller->execute();
}
}
13 changes: 11 additions & 2 deletions app/code/Magento/Rss/Test/Unit/Controller/Feed/IndexTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ protected function setUp()
->disableOriginalConstructor()->getMock();

$objectManagerHelper = new ObjectManagerHelper($this);

$this->controller = $objectManagerHelper->getObject(
\Magento\Rss\Controller\Feed\Index::class,
[
Expand Down Expand Up @@ -90,14 +91,22 @@ public function testExecuteWithException()
$dataProvider = $this->getMock(\Magento\Framework\App\Rss\DataProviderInterface::class);
$dataProvider->expects($this->once())->method('isAllowed')->will($this->returnValue(true));

$rssModel = $this->getMock(\Magento\Rss\Model\Rss::class, ['setDataProvider'], [], '', false);
$rssModel = $this->getMock(\Magento\Rss\Model\Rss::class, ['setDataProvider', 'createRssXml'], [], '', false);
$rssModel->expects($this->once())->method('setDataProvider')->will($this->returnSelf());

$exceptionMock = new \Magento\Framework\Exception\RuntimeException(
new \Magento\Framework\Phrase('Any message')
);

$rssModel->expects($this->once())->method('createRssXml')->will(
$this->throwException($exceptionMock)
);

$this->response->expects($this->once())->method('setHeader')->will($this->returnSelf());
$this->rssFactory->expects($this->once())->method('create')->will($this->returnValue($rssModel));
$this->rssManager->expects($this->once())->method('getProvider')->will($this->returnValue($dataProvider));

$this->setExpectedException('\Zend_Feed_Builder_Exception');
$this->setExpectedException(\Magento\Framework\Exception\RuntimeException::class);
$this->controller->execute();
}
}
46 changes: 45 additions & 1 deletion app/code/Magento/Rss/Test/Unit/Model/RssTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ class RssTest extends \PHPUnit_Framework_TestCase
/**
* @var array
*/
protected $feedData = [
private $feedData = [
'title' => 'Feed Title',
'link' => 'http://magento.com/rss/link',
'description' => 'Feed Description',
Expand All @@ -33,6 +33,27 @@ class RssTest extends \PHPUnit_Framework_TestCase
],
];

/**
* @var string
*/
private $feedXml = '<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:content="http://purl.org/rss/1.0/modules/content/" version="2.0">
<channel>
<title><![CDATA[Feed Title]]></title>
<link>http://magento.com/rss/link</link>
<description><![CDATA[Feed Description]]></description>
<pubDate>Sat, 22 Apr 2017 13:21:12 +0200</pubDate>
<generator>Zend_Feed</generator>
<docs>http://blogs.law.harvard.edu/tech/rss</docs>
<item>
<title><![CDATA[Feed 1 Title]]></title>
<link>http://magento.com/rss/link/id/1</link>
<description><![CDATA[Feed 1 Description]]></description>
<pubDate>Sat, 22 Apr 2017 13:21:12 +0200</pubDate>
</item>
</channel>
</rss>';

/**
* @var ObjectManagerHelper
*/
Expand All @@ -43,6 +64,16 @@ class RssTest extends \PHPUnit_Framework_TestCase
*/
private $cacheMock;

/**
* @var \Magento\Framework\App\FeedImporterInterface|\PHPUnit_Framework_MockObject_MockObject
*/
private $feedImporterMock;

/**
* @var \Magento\Framework\App\FeedInterface|\PHPUnit_Framework_MockObject_MockObject
*/
private $feedMock;

/**
* @var SerializerInterface|\PHPUnit_Framework_MockObject_MockObject
*/
Expand All @@ -52,11 +83,15 @@ protected function setUp()
{
$this->cacheMock = $this->getMock(\Magento\Framework\App\CacheInterface::class);
$this->serializerMock = $this->getMock(SerializerInterface::class);
$this->feedImporterMock = $this->getMock(\Magento\Framework\App\FeedImporterInterface::class);
$this->feedMock = $this->getMock(\Magento\Framework\App\FeedInterface::class);

$this->objectManagerHelper = new ObjectManagerHelper($this);
$this->rss = $this->objectManagerHelper->getObject(
\Magento\Rss\Model\Rss::class,
[
'cache' => $this->cacheMock,
'feedImporter' => $this->feedImporterMock,
'serializer' => $this->serializerMock
]
);
Expand Down Expand Up @@ -116,6 +151,15 @@ public function testCreateRssXml()
$dataProvider->expects($this->any())->method('getCacheLifetime')->will($this->returnValue(100));
$dataProvider->expects($this->any())->method('getRssData')->will($this->returnValue($this->feedData));

$this->feedMock->expects($this->once())
->method('asXml')
->will($this->returnValue($this->feedXml));

$this->feedImporterMock->expects($this->once())
->method('importArray')
->with($this->feedData)
->will($this->returnValue($this->feedMock));

$this->rss->setDataProvider($dataProvider);
$result = $this->rss->createRssXml();
$this->assertContains('<?xml version="1.0" encoding="UTF-8"?>', $result);
Expand Down
2 changes: 2 additions & 0 deletions app/etc/di.xml
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,8 @@
<preference for="Magento\Framework\App\View\Deployment\Version\StorageInterface" type="Magento\Framework\App\View\Deployment\Version\Storage\File"/>
<preference for="Magento\Framework\View\Page\FaviconInterface" type="Magento\Theme\Model\Favicon\Favicon" />
<preference for="Magento\Framework\View\Element\Message\InterpretationStrategyInterface" type="Magento\Framework\View\Element\Message\InterpretationMediator" />
<preference for="Magento\Framework\App\FeedInterface" type="Magento\Framework\App\Feed" />
<preference for="Magento\Framework\App\FeedImporterInterface" type="Magento\Framework\App\Feed\Importer" />
<type name="Magento\Framework\Model\ResourceModel\Db\TransactionManager" shared="false" />
<type name="Magento\Framework\Acl\Data\Cache">
<arguments>
Expand Down
32 changes: 32 additions & 0 deletions lib/internal/Magento/Framework/App/Feed.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
namespace Magento\Framework\App;

class Feed implements \Magento\Framework\App\FeedInterface
{
/**
* @var \Magento\Framework\App\FeedImporterInterface
*/
private $feed;

/**
* @param \Zend_Feed_Abstract $feed
*/
public function __construct(\Zend_Feed_Abstract $feed)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please provide supported formats argument, configurable through DI.
As described below, to have a possibility verify whether supported format passed to getFormatedContentAs method

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense.

{
$this->feed = $feed;
}

/**
* Get the xml from Zend_Feed_Abstract object
*
* @return string
*/
public function asXml()
{
return $this->feed->saveXml();
}
}
68 changes: 68 additions & 0 deletions lib/internal/Magento/Framework/App/Feed/Importer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
namespace Magento\Framework\App\Feed;

use Magento\Framework\App\FeedFactory;
use Psr\Log\LoggerInterface;

/**
* Feed importer
*/
class Importer implements \Magento\Framework\App\FeedImporterInterface
{
/**
* @var \Zend_Feed
*/
private $feedProcessor;

/**
* @var FeedFactory
*/
private $feedFactory;

/**
* @var LoggerInterface
*/
private $logger;

/**
* @param \Zend_Feed $feedProcessor
* @param FeedFactory $feedFactory
* @param LoggerInterface $logger
*/
public function __construct(
\Zend_Feed $feedProcessor,
FeedFactory $feedFactory,
LoggerInterface $logger
) {
$this->feedProcessor = $feedProcessor;
$this->feedFactory = $feedFactory;
$this->logger = $logger;
}

/**
* Get a new \Magento\Framework\App\Feed object from a custom array
*
* @throws \Magento\Framework\Exception\RuntimeException
* @param array $data
* @param string $format
* @return \Magento\Framework\App\FeedInterface
*/
public function importArray(array $data, $format = 'atom')
{

try {
$feed = $this->feedProcessor->importArray($data, $format);
return $this->feedFactory->create(['feed' => $feed]);
} catch (\Zend_Feed_Exception $e) {
$this->logger->error($e->getMessage());
throw new \Magento\Framework\Exception\RuntimeException(
__('There has been an error with import'),
$e
);
}
}
}
20 changes: 20 additions & 0 deletions lib/internal/Magento/Framework/App/FeedImporterInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
namespace Magento\Framework\App;

interface FeedImporterInterface
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe make sense to rename this interface to
FeedFactoryInterface ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure about this, why do you think that it should be renamed to factory, it doesn't create new objects?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like it creates. Description from the importArray method says:
Get a new \Magento\Framework\App\Feed object from a custom array
and implementation looks like:

$feed = $this->feedProcessor->importArray($data, $format);
 return $this->feedFactory->create(['feed' => $feed]);

for now it's not clear why it's called importer? From where it imports data?
Looking at the interface and implementation I see FeedFactory which accepts array of data and format

For me it's not clear why we need to keep both objects
\Magento\Framework\App\Feed\Importer
and
FeedFactory

Because both of them responsible for \Magento\Framework\App\FeedInterface creation.

I propose to get rid of \Magento\Framework\App\Feed\Importer and move it's logic to FeedFactory.

Thus, FeedFactoryInterface would look like:

class FeedFactoryInterface
{
public function importArray(array $data, $format = SupportedFeedFormatsInterface::DEFAULT_FORMAT)
}

{

/**
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please provide a precise description what this method is actually do

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

* Returns FeedInterface object from a custom array
*
* @throws \Magento\Framework\Exception\RuntimeException
* @param array $data
* @param string $format
* @return FeedInterface
*/
public function importArray(array $data, $format = 'atom');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's not good from interface point of view, that 'atom' passed as a default parameter.

What other formats does this Importer support?
It's not clear from the interface.
And not clear how to check this out.
Interface should be clear enough to get this knowledge

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see your point but I did it because I wanted to replicate the original importArray method from Zend_Feed which has those arguments. What would be the best thing to do in this case?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not always a good Idea to replicate contracts from Zend. Because sometimes we would provide a wider contract than Zend does, and sometimes their contracts are not so ideal.
Above I described my idea what we can do with this

}
14 changes: 14 additions & 0 deletions lib/internal/Magento/Framework/App/FeedInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
namespace Magento\Framework\App;

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please provide description for the interface

interface FeedInterface
{
/**
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please provide description of input data in PHP Doc Block

* @return string
*/
public function asXml();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I prefer to see this method as

public function getFormatedContentAs($format = SupportedFeedFormatsInterface::DEFAULT_FORMAT);

Naming could be changed, but main idea is to make FeedInteface agnostic to the possible representation formats.
Because we no need to have coupling between Data and different ways how these data could be presented.
Thus, all that we need to have is kind of "output" method which accepts a format in which data should be presented. And we need to have a dedicated interface/entity responsible for format registration.
I mentioned SupportedFeedFormatsInterface here

}