Skip to content

Commit 6a8f235

Browse files
author
Denis Slepnev
committed
Added Admin Grid: Google Shopping Feeds; Added Admin menu section: run_as_root
1 parent b063d85 commit 6a8f235

28 files changed

+867
-19
lines changed

Api/Data/FeedInterface.php

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
<?php
2+
3+
namespace RunAsRoot\GoogleShoppingFeed\Api\Data;
4+
5+
interface FeedInterface
6+
{
7+
const FILENAME = 'filename';
8+
9+
const PATH = 'path';
10+
11+
const LINK = 'link';
12+
13+
const LAST_GENERATED = 'last_generated';
14+
15+
const STORE = 'store';
16+
17+
/**
18+
* Feed file name
19+
*
20+
* @return string
21+
*/
22+
public function getFileName(): string;
23+
24+
/**
25+
* @param string $fileName
26+
*
27+
* @return $this
28+
*/
29+
public function setFileName(string $fileName): FeedInterface;
30+
31+
/**
32+
* Feed media path
33+
*
34+
* @return string
35+
*/
36+
public function getPath(): string;
37+
38+
/**
39+
* @param string $path
40+
*
41+
* @return $this
42+
*/
43+
public function setPath(string $path): FeedInterface;
44+
45+
/**
46+
* Feed Link for Google
47+
*
48+
* @return string
49+
*/
50+
public function getLink(): string;
51+
52+
/**
53+
* @param string $link
54+
*
55+
* @return $this
56+
*/
57+
public function setLink(string $link): FeedInterface;
58+
59+
/**
60+
* Feed Last Generated Time
61+
*
62+
* @return string
63+
*/
64+
public function getLastGenerated(): string;
65+
66+
/**
67+
* @param string $lastGenerated
68+
*
69+
* @return $this
70+
*/
71+
public function setLastGenerated(string $lastGenerated): FeedInterface;
72+
73+
/**
74+
* Feed Store View
75+
*
76+
* @return string
77+
*/
78+
public function getStore(): string;
79+
80+
/**
81+
* @param string $store
82+
*
83+
* @return $this
84+
*/
85+
public function setStore(string $store): FeedInterface;
86+
}

Api/FeedRepositoryInterface.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<?php
2+
3+
namespace RunAsRoot\GoogleShoppingFeed\Api;
4+
5+
use RunAsRoot\GoogleShoppingFeed\Api\Data\FeedInterface;
6+
7+
interface FeedRepositoryInterface
8+
{
9+
/**
10+
* Retrieve list of feeds
11+
*
12+
* @return FeedInterface[]
13+
*/
14+
public function getList(): array;
15+
}

Controller/Adminhtml/Google/Feeds.php

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<?php
2+
3+
namespace RunAsRoot\GoogleShoppingFeed\Controller\Adminhtml\Google;
4+
5+
class Feeds extends \Magento\Backend\App\Action
6+
{
7+
protected $resultPageFactory = false;
8+
9+
public function __construct(
10+
\Magento\Backend\App\Action\Context $context,
11+
\Magento\Framework\View\Result\PageFactory $resultPageFactory
12+
)
13+
{
14+
parent::__construct($context);
15+
$this->resultPageFactory = $resultPageFactory;
16+
}
17+
18+
public function execute()
19+
{
20+
$resultPage = $this->resultPageFactory->create();
21+
$resultPage->getConfig()->getTitle()->prepend((__('Google Shopping Feeds')));
22+
23+
return $resultPage;
24+
}
25+
}

Model/Feed.php

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
<?php
2+
3+
namespace RunAsRoot\GoogleShoppingFeed\Model;
4+
5+
use RunAsRoot\GoogleShoppingFeed\Api\Data\FeedInterface;
6+
7+
class Feed extends \Magento\Framework\Model\AbstractExtensibleModel
8+
implements \RunAsRoot\GoogleShoppingFeed\Api\Data\FeedInterface
9+
{
10+
11+
/**
12+
* @inheritDoc
13+
*/
14+
public function getFileName(): string
15+
{
16+
return $this->getData(self::FILENAME);
17+
}
18+
19+
/**
20+
* @inheritDoc
21+
*/
22+
public function setFileName(string $fileName): FeedInterface
23+
{
24+
return $this->setData(self::FILENAME, $fileName);
25+
}
26+
27+
/**
28+
* @inheritDoc
29+
*/
30+
public function getPath(): string
31+
{
32+
return $this->getData(self::PATH);
33+
}
34+
35+
/**
36+
* @inheritDoc
37+
*/
38+
public function setPath(string $path): FeedInterface
39+
{
40+
return $this->setData(self::PATH, $path);
41+
}
42+
43+
/**
44+
* @inheritDoc
45+
*/
46+
public function getLink(): string
47+
{
48+
return $this->getData(self::LINK);
49+
}
50+
51+
/**
52+
* @inheritDoc
53+
*/
54+
public function setLink(string $link): FeedInterface
55+
{
56+
return $this->setData(self::LINK, $link);
57+
}
58+
59+
/**
60+
* @inheritDoc
61+
*/
62+
public function getLastGenerated(): string
63+
{
64+
return $this->getData(self::LAST_GENERATED);
65+
}
66+
67+
/**
68+
* @inheritDoc
69+
*/
70+
public function setLastGenerated(string $lastGenerated): FeedInterface
71+
{
72+
return $this->setData(self::LAST_GENERATED, $lastGenerated);
73+
}
74+
75+
/**
76+
* @inheritDoc
77+
*/
78+
public function getStore(): string
79+
{
80+
return $this->getData(self::STORE);
81+
}
82+
83+
/**
84+
* @inheritDoc
85+
*/
86+
public function setStore(string $store): FeedInterface
87+
{
88+
return $this->setData(self::STORE, $store);
89+
}
90+
}

Model/FeedRepository.php

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
<?php
2+
3+
namespace RunAsRoot\GoogleShoppingFeed\Model;
4+
5+
use Magento\Framework\Exception\LocalizedException;
6+
use Magento\Framework\Exception\NoSuchEntityException;
7+
use RunAsRoot\GoogleShoppingFeed\Reader\FileReaderProvider;
8+
9+
class FeedRepository implements \RunAsRoot\GoogleShoppingFeed\Api\FeedRepositoryInterface
10+
{
11+
private FileReaderProvider $fileReaderProvider;
12+
13+
private FeedFactory $feedFactory;
14+
15+
public function __construct(
16+
FileReaderProvider $fileReaderProvider,
17+
FeedFactory $feedFactory
18+
)
19+
{
20+
$this->fileReaderProvider = $fileReaderProvider;
21+
$this->feedFactory = $feedFactory;
22+
}
23+
24+
/**
25+
* @inheritDoc
26+
* @throws NoSuchEntityException
27+
* @throws LocalizedException
28+
*/
29+
public function getList(): array
30+
{
31+
$fileReader = $this->fileReaderProvider->get();
32+
33+
try {
34+
$files = $fileReader->read();
35+
} catch (LocalizedException $e) {
36+
throw new LocalizedException(__($e->getMessage()));
37+
}
38+
39+
$feeds = [];
40+
41+
foreach ($files as $file) {
42+
/** @var Feed $feed */
43+
$feed = $this->feedFactory->create();
44+
45+
$feed->setFileName($file['fileName']);
46+
$feed->setPath($file['path']);
47+
$feed->setLink($file['link']);
48+
$feed->setLastGenerated($file['fileGenerationTime']);
49+
$feed->setStore($file['store']);
50+
51+
$feeds[] = $feed->toArray();
52+
}
53+
54+
55+
return $feeds;
56+
}
57+
}

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,3 +80,7 @@ Performs iteration on all products provided by this collection provider `\RunAsR
8080
### Add new attribute to feed
8181
1. Create new attribute data provider. @see interface `\RunAsRoot\GoogleShoppingFeed\DataProvider\AttributeHandlers\AttributeHandlerInterface`.
8282
2. Add configuration for new attribute in `\RunAsRoot\GoogleShoppingFeed\Enum\AttributesToImportEnumInterface::ATTRIBUTES`.
83+
84+
## Google Shopping Feeds Grid
85+
Generated feeds could be reviewed inside Admin Backoffice
86+
* Navigate to Marketing -> run_as_root -> Google Shopping Feed

Reader/FileReader.php

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
<?php
2+
3+
namespace RunAsRoot\GoogleShoppingFeed\Reader;
4+
5+
use Magento\Framework\App\Filesystem\DirectoryList;
6+
use Magento\Framework\Exception\LocalizedException;
7+
use Magento\Framework\Exception\NoSuchEntityException;
8+
use Magento\Framework\Phrase;
9+
use Magento\Framework\UrlInterface;
10+
use FilesystemIterator;
11+
use FilesystemIteratorFactory;
12+
use DateTime;
13+
14+
15+
class FileReader
16+
{
17+
private UrlInterface $urlBuilder;
18+
19+
private FilesystemIteratorFactory $filesystemIteratorFactory;
20+
21+
private DateTime $dateTime;
22+
23+
private string $destination;
24+
25+
public function __construct(
26+
UrlInterface $urlBuilder,
27+
FilesystemIteratorFactory $filesystemIteratorFactory,
28+
DateTime $dateTime
29+
)
30+
{
31+
$this->urlBuilder = $urlBuilder;
32+
$this->filesystemIteratorFactory = $filesystemIteratorFactory;
33+
$this->dateTime = $dateTime;
34+
}
35+
36+
/**
37+
* @throws NoSuchEntityException
38+
* @throws LocalizedException
39+
*/
40+
public function read(): array
41+
{
42+
if (empty($this->destination)) {
43+
throw new LocalizedException(
44+
new Phrase('The destination is not set')
45+
);
46+
}
47+
48+
try {
49+
$dir = $this->filesystemIteratorFactory->create([
50+
'path' => DirectoryList::MEDIA . DIRECTORY_SEPARATOR . $this->destination,
51+
'flags' => FilesystemIterator::SKIP_DOTS
52+
]);
53+
} catch (\UnexpectedValueException $exception) {
54+
return [];
55+
}
56+
57+
$result = [];
58+
$storeMediaUrl = $this->urlBuilder->getBaseUrl(['_type' => UrlInterface::URL_TYPE_MEDIA]);
59+
60+
while ($dir->valid()) {
61+
if (!$dir->isDir()) {
62+
$this->dateTime->setTimestamp($dir->getMTime());
63+
$fileGenerationTime = $this->dateTime->format('Y-m-d H:i:s');
64+
$fileName = $dir->getFilename();
65+
$stores = null;
66+
preg_match('/_store_(\w+)_feed/', $fileName, $stores);
67+
$result[] = [
68+
'path' => $dir->getPath() . DIRECTORY_SEPARATOR . $fileName,
69+
'fileGenerationTime' => $fileGenerationTime,
70+
'link' => $storeMediaUrl . $dir,
71+
'fileName' => $fileName,
72+
'store' => $stores[1] ?? 'default'
73+
];
74+
}
75+
76+
$dir->next();
77+
}
78+
79+
return $result;
80+
}
81+
82+
public function setDestination(string $value): FileReader
83+
{
84+
$this->destination = $value;
85+
return $this;
86+
}
87+
}

0 commit comments

Comments
 (0)