Version Notes
Release 2.2.0 notes:
- Existing images are not remigrated during migration, and do not fail migration
- Fix bug where migration status shows value above 100%
- Preserve original file extensions in Cloudinary image urls
- Retry migration when network failures occur
Download this release
Release Info
Developer | Cloudinary |
Extension | Cloudinary_Cloudinary |
Version | 2.2.0 |
Comparing to | |
See all releases |
Code changes from version 2.1.0 to 2.2.0
- app/code/community/Cloudinary/Cloudinary/Model/Cron.php +7 -5
- app/code/community/Cloudinary/Cloudinary/Model/MigrationError.php +18 -0
- app/code/community/Cloudinary/Cloudinary/Model/Resource/Cms/Synchronisation/Collection.php +55 -0
- app/code/community/Cloudinary/Cloudinary/Model/Resource/Synchronisation/Collection.php +9 -0
- app/code/community/Cloudinary/Cloudinary/Model/SynchronisedMediaUnifier.php +39 -9
- app/code/community/Cloudinary/Cloudinary/controllers/Adminhtml/CloudinaryController.php +21 -0
- app/code/community/Cloudinary/Cloudinary/etc/config.xml +1 -1
- lib/CloudinaryExtension/CloudinaryImageManager.php +41 -4
- lib/CloudinaryExtension/CloudinaryImageProvider.php +8 -8
- lib/CloudinaryExtension/Exception/ApiError.php +8 -0
- lib/CloudinaryExtension/Exception/FileExists.php +8 -0
- lib/CloudinaryExtension/Exception/MigrationError.php +18 -20
- lib/CloudinaryExtension/Image.php +14 -5
- lib/CloudinaryExtension/Image/Transformation.php +0 -26
- lib/CloudinaryExtension/Image/Transformation/FetchFormat.php +5 -0
- lib/CloudinaryExtension/Image/Transformation/Format.php +0 -25
- lib/CloudinaryExtension/Migration/BatchUploader.php +106 -18
- lib/CloudinaryExtension/Migration/SynchronizedMediaRepository.php +1 -0
- lib/CloudinaryExtension/UploadResponseValidator.php +2 -2
- lib/CloudinaryExtension/UrlGenerator.php +5 -8
- package.xml +10 -9
app/code/community/Cloudinary/Cloudinary/Model/Cron.php
CHANGED
@@ -1,6 +1,7 @@
|
|
1 |
<?php
|
2 |
|
3 |
use CloudinaryExtension\CloudinaryImageProvider;
|
|
|
4 |
use CloudinaryExtension\Migration\BatchUploader;
|
5 |
|
6 |
class Cloudinary_Cloudinary_Model_Cron extends Mage_Core_Model_Abstract
|
@@ -22,7 +23,12 @@ class Cloudinary_Cloudinary_Model_Cron extends Mage_Core_Model_Abstract
|
|
22 |
),
|
23 |
$migrationTask,
|
24 |
Mage::getModel('cloudinary_cloudinary/logger'),
|
25 |
-
null
|
|
|
|
|
|
|
|
|
|
|
26 |
);
|
27 |
|
28 |
$combinedMediaRepository = new Cloudinary_Cloudinary_Model_SynchronisedMediaUnifier(
|
@@ -41,10 +47,6 @@ class Cloudinary_Cloudinary_Model_Cron extends Mage_Core_Model_Abstract
|
|
41 |
|
42 |
$migrationQueue->process();
|
43 |
|
44 |
-
foreach ($batchUploader->getMigrationErrors() as $error) {
|
45 |
-
Cloudinary_Cloudinary_Model_MigrationError::saveFromException($error);
|
46 |
-
}
|
47 |
-
|
48 |
return $this;
|
49 |
}
|
50 |
}
|
1 |
<?php
|
2 |
|
3 |
use CloudinaryExtension\CloudinaryImageProvider;
|
4 |
+
use CloudinaryExtension\Exception\MigrationError;
|
5 |
use CloudinaryExtension\Migration\BatchUploader;
|
6 |
|
7 |
class Cloudinary_Cloudinary_Model_Cron extends Mage_Core_Model_Abstract
|
23 |
),
|
24 |
$migrationTask,
|
25 |
Mage::getModel('cloudinary_cloudinary/logger'),
|
26 |
+
null,
|
27 |
+
function(\Exception $e) {
|
28 |
+
if ($e instanceof MigrationError) {
|
29 |
+
Cloudinary_Cloudinary_Model_MigrationError::saveFromException($e);
|
30 |
+
}
|
31 |
+
}
|
32 |
);
|
33 |
|
34 |
$combinedMediaRepository = new Cloudinary_Cloudinary_Model_SynchronisedMediaUnifier(
|
47 |
|
48 |
$migrationQueue->process();
|
49 |
|
|
|
|
|
|
|
|
|
50 |
return $this;
|
51 |
}
|
52 |
}
|
app/code/community/Cloudinary/Cloudinary/Model/MigrationError.php
CHANGED
@@ -3,11 +3,16 @@
|
|
3 |
|
4 |
class Cloudinary_Cloudinary_Model_MigrationError extends Mage_Core_Model_Abstract
|
5 |
{
|
|
|
|
|
6 |
public function __construct()
|
7 |
{
|
8 |
$this->_init('cloudinary_cloudinary/migrationError');
|
9 |
}
|
10 |
|
|
|
|
|
|
|
11 |
public static function saveFromException(\CloudinaryExtension\Exception\MigrationError $e)
|
12 |
{
|
13 |
$image = $e->getImage();
|
@@ -23,4 +28,17 @@ class Cloudinary_Cloudinary_Model_MigrationError extends Mage_Core_Model_Abstrac
|
|
23 |
|
24 |
$entry->save();
|
25 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
26 |
}
|
3 |
|
4 |
class Cloudinary_Cloudinary_Model_MigrationError extends Mage_Core_Model_Abstract
|
5 |
{
|
6 |
+
const REMOVE_ORPHAN_MESSAGE = 'Image found in sync table that no longer exists. Removing reference: %s';
|
7 |
+
|
8 |
public function __construct()
|
9 |
{
|
10 |
$this->_init('cloudinary_cloudinary/migrationError');
|
11 |
}
|
12 |
|
13 |
+
/**
|
14 |
+
* @param \CloudinaryExtension\Exception\MigrationError $e
|
15 |
+
*/
|
16 |
public static function saveFromException(\CloudinaryExtension\Exception\MigrationError $e)
|
17 |
{
|
18 |
$image = $e->getImage();
|
28 |
|
29 |
$entry->save();
|
30 |
}
|
31 |
+
|
32 |
+
/**
|
33 |
+
* @param Cloudinary_Cloudinary_Model_Synchronisation $orphanImage
|
34 |
+
* @return $this
|
35 |
+
*/
|
36 |
+
public function orphanRemoved(Cloudinary_Cloudinary_Model_Synchronisation $orphanImage)
|
37 |
+
{
|
38 |
+
$this->setFilePath($orphanImage->getImageName());
|
39 |
+
$this->setRelativePath($orphanImage->getImageName());
|
40 |
+
$this->setMessage(sprintf(self::REMOVE_ORPHAN_MESSAGE, $orphanImage->getImageName()));
|
41 |
+
$this->setTimestamp(time());
|
42 |
+
return $this;
|
43 |
+
}
|
44 |
}
|
app/code/community/Cloudinary/Cloudinary/Model/Resource/Cms/Synchronisation/Collection.php
CHANGED
@@ -1,5 +1,6 @@
|
|
1 |
<?php
|
2 |
|
|
|
3 |
use CloudinaryExtension\Migration\SynchronizedMediaRepository;
|
4 |
|
5 |
class Cloudinary_Cloudinary_Model_Resource_Cms_Synchronisation_Collection
|
@@ -38,6 +39,9 @@ class Cloudinary_Cloudinary_Model_Resource_Cms_Synchronisation_Collection
|
|
38 |
}
|
39 |
}
|
40 |
|
|
|
|
|
|
|
41 |
public function findUnsynchronisedImages()
|
42 |
{
|
43 |
$helperConfig = Mage::getModel('cloudinary_cloudinary/configuration');
|
@@ -70,4 +74,55 @@ class Cloudinary_Cloudinary_Model_Resource_Cms_Synchronisation_Collection
|
|
70 |
->addFieldToFilter('media_gallery_id', array('null' => true))
|
71 |
->getData();
|
72 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
73 |
}
|
1 |
<?php
|
2 |
|
3 |
+
use CloudinaryExtension\Image\Synchronizable;
|
4 |
use CloudinaryExtension\Migration\SynchronizedMediaRepository;
|
5 |
|
6 |
class Cloudinary_Cloudinary_Model_Resource_Cms_Synchronisation_Collection
|
39 |
}
|
40 |
}
|
41 |
|
42 |
+
/**
|
43 |
+
* @return [Cloudinary_Cloudinary_Model_Synchronisation]
|
44 |
+
*/
|
45 |
public function findUnsynchronisedImages()
|
46 |
{
|
47 |
$helperConfig = Mage::getModel('cloudinary_cloudinary/configuration');
|
74 |
->addFieldToFilter('media_gallery_id', array('null' => true))
|
75 |
->getData();
|
76 |
}
|
77 |
+
|
78 |
+
private function _getSynchronisedRawImageNames()
|
79 |
+
{
|
80 |
+
$result = array_map(
|
81 |
+
function ($itemData) {
|
82 |
+
return $itemData['image_name'];
|
83 |
+
},
|
84 |
+
$this->_getSynchronisedImageData()
|
85 |
+
);
|
86 |
+
|
87 |
+
return $result;
|
88 |
+
}
|
89 |
+
|
90 |
+
/**
|
91 |
+
* @return [Cloudinary_Cloudinary_Model_Synchronisation]
|
92 |
+
*/
|
93 |
+
public function findOrphanedSynchronisedImages()
|
94 |
+
{
|
95 |
+
return $this->_synchronisationCollectionFromImageNames(
|
96 |
+
array_diff(
|
97 |
+
$this->_getSynchronisedRawImageNames(),
|
98 |
+
$this->_extractRelativePaths($this->getItems())
|
99 |
+
)
|
100 |
+
);
|
101 |
+
}
|
102 |
+
|
103 |
+
/**
|
104 |
+
* @param [string] $imageNames
|
105 |
+
* @return [Cloudinary_Cloudinary_Model_Synchronisation]
|
106 |
+
*/
|
107 |
+
private function _synchronisationCollectionFromImageNames(array $imageNames)
|
108 |
+
{
|
109 |
+
return Mage::getModel('cloudinary_cloudinary/synchronisation')
|
110 |
+
->getCollection()
|
111 |
+
->addFieldToFilter('image_name', ['in' => $imageNames])
|
112 |
+
->getItems();
|
113 |
+
}
|
114 |
+
|
115 |
+
/**
|
116 |
+
* @param [Synchronizable] $items
|
117 |
+
* @return [string]
|
118 |
+
*/
|
119 |
+
private function _extractRelativePaths(array $items)
|
120 |
+
{
|
121 |
+
return array_map(
|
122 |
+
function(Synchronizable $syncItem) {
|
123 |
+
return $syncItem->getRelativePath();
|
124 |
+
},
|
125 |
+
$items
|
126 |
+
);
|
127 |
+
}
|
128 |
}
|
app/code/community/Cloudinary/Cloudinary/Model/Resource/Synchronisation/Collection.php
CHANGED
@@ -60,4 +60,13 @@ class Cloudinary_Cloudinary_Model_Resource_Synchronisation_Collection
|
|
60 |
$select->where('media_gallery_value is not null');
|
61 |
return $select->columns('media_gallery_value');
|
62 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
63 |
}
|
60 |
$select->where('media_gallery_value is not null');
|
61 |
return $select->columns('media_gallery_value');
|
62 |
}
|
63 |
+
|
64 |
+
/**
|
65 |
+
* Only applicable for cms instance
|
66 |
+
* @return [Cloudinary_Cloudinary_Model_Synchronisation]
|
67 |
+
*/
|
68 |
+
public function findOrphanedSynchronisedImages()
|
69 |
+
{
|
70 |
+
return [];
|
71 |
+
}
|
72 |
}
|
app/code/community/Cloudinary/Cloudinary/Model/SynchronisedMediaUnifier.php
CHANGED
@@ -4,24 +4,54 @@ use CloudinaryExtension\Migration\SynchronizedMediaRepository;
|
|
4 |
|
5 |
class Cloudinary_Cloudinary_Model_SynchronisedMediaUnifier implements SynchronizedMediaRepository
|
6 |
{
|
7 |
-
|
|
|
|
|
8 |
private $_synchronisedMediaRepositories;
|
9 |
-
private $_unsychronisedImages = array();
|
10 |
|
|
|
|
|
|
|
|
|
11 |
public function __construct(array $synchronisedMediaRepositories)
|
12 |
{
|
13 |
$this->_synchronisedMediaRepositories = $synchronisedMediaRepositories;
|
14 |
}
|
15 |
|
|
|
|
|
|
|
|
|
16 |
public function findUnsynchronisedImages($limit = 200)
|
17 |
{
|
18 |
-
|
19 |
-
|
20 |
-
|
21 |
-
|
22 |
-
|
23 |
-
|
24 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
25 |
}
|
26 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
27 |
}
|
4 |
|
5 |
class Cloudinary_Cloudinary_Model_SynchronisedMediaUnifier implements SynchronizedMediaRepository
|
6 |
{
|
7 |
+
/**
|
8 |
+
* @var [SynchronizedMediaRepository]
|
9 |
+
*/
|
10 |
private $_synchronisedMediaRepositories;
|
|
|
11 |
|
12 |
+
/**
|
13 |
+
* Cloudinary_Cloudinary_Model_SynchronisedMediaUnifier constructor.
|
14 |
+
* @param [SynchronizedMediaRepository]
|
15 |
+
*/
|
16 |
public function __construct(array $synchronisedMediaRepositories)
|
17 |
{
|
18 |
$this->_synchronisedMediaRepositories = $synchronisedMediaRepositories;
|
19 |
}
|
20 |
|
21 |
+
/**
|
22 |
+
* @param int $limit
|
23 |
+
* @return [Cloudinary_Cloudinary_Model_Synchronisation]
|
24 |
+
*/
|
25 |
public function findUnsynchronisedImages($limit = 200)
|
26 |
{
|
27 |
+
return array_slice($this->findUnlimitedUnsynchronisedImages(), 0, $limit);
|
28 |
+
}
|
29 |
+
|
30 |
+
/**
|
31 |
+
* @return [Cloudinary_Cloudinary_Model_Synchronisation]
|
32 |
+
*/
|
33 |
+
private function findUnlimitedUnsynchronisedImages()
|
34 |
+
{
|
35 |
+
return array_reduce(
|
36 |
+
$this->_synchronisedMediaRepositories,
|
37 |
+
function($carry, $synchronisedMediaRepository) {
|
38 |
+
return $carry + $synchronisedMediaRepository->findUnsynchronisedImages();
|
39 |
+
},
|
40 |
+
[]
|
41 |
+
);
|
42 |
}
|
43 |
|
44 |
+
/**
|
45 |
+
* @return [Cloudinary_Cloudinary_Model_Synchronisation]
|
46 |
+
*/
|
47 |
+
public function findOrphanedSynchronisedImages()
|
48 |
+
{
|
49 |
+
return array_reduce(
|
50 |
+
$this->_synchronisedMediaRepositories,
|
51 |
+
function($carry, $synchronisedMediaRepository) {
|
52 |
+
return $carry + $synchronisedMediaRepository->findOrphanedSynchronisedImages();
|
53 |
+
},
|
54 |
+
[]
|
55 |
+
);
|
56 |
+
}
|
57 |
}
|
app/code/community/Cloudinary/Cloudinary/controllers/Adminhtml/CloudinaryController.php
CHANGED
@@ -4,6 +4,9 @@ class Cloudinary_Cloudinary_Adminhtml_CloudinaryController extends Mage_Adminhtm
|
|
4 |
{
|
5 |
const CRON_INTERVAL = 300;
|
6 |
|
|
|
|
|
|
|
7 |
private $_migrationTask;
|
8 |
|
9 |
/**
|
@@ -21,6 +24,8 @@ class Cloudinary_Cloudinary_Adminhtml_CloudinaryController extends Mage_Adminhtm
|
|
21 |
|
22 |
public function indexAction()
|
23 |
{
|
|
|
|
|
24 |
$this->_displayMigrationMessages();
|
25 |
|
26 |
$layout = $this->loadLayout();
|
@@ -43,6 +48,22 @@ class Cloudinary_Cloudinary_Adminhtml_CloudinaryController extends Mage_Adminhtm
|
|
43 |
$this->renderLayout();
|
44 |
}
|
45 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
46 |
public function configAction()
|
47 |
{
|
48 |
$this->_redirect("*/system_config/edit/section/cloudinary/");
|
4 |
{
|
5 |
const CRON_INTERVAL = 300;
|
6 |
|
7 |
+
/**
|
8 |
+
* @var Cloudinary_Cloudinary_Model_Migration
|
9 |
+
*/
|
10 |
private $_migrationTask;
|
11 |
|
12 |
/**
|
24 |
|
25 |
public function indexAction()
|
26 |
{
|
27 |
+
$this->removeOrphanSyncEntries();
|
28 |
+
|
29 |
$this->_displayMigrationMessages();
|
30 |
|
31 |
$layout = $this->loadLayout();
|
48 |
$this->renderLayout();
|
49 |
}
|
50 |
|
51 |
+
public function removeOrphanSyncEntries()
|
52 |
+
{
|
53 |
+
$combinedMediaRepository = Mage::getModel(
|
54 |
+
'cloudinary_cloudinary/synchronisedMediaUnifier',
|
55 |
+
[
|
56 |
+
Mage::getResourceModel('cloudinary_cloudinary/synchronisation_collection'),
|
57 |
+
Mage::getResourceModel('cloudinary_cloudinary/cms_synchronisation_collection')
|
58 |
+
]
|
59 |
+
);
|
60 |
+
|
61 |
+
foreach ($combinedMediaRepository->findOrphanedSynchronisedImages() as $orphanImage) {
|
62 |
+
Mage::getModel('cloudinary_cloudinary/migrationError')->orphanRemoved($orphanImage)->save();
|
63 |
+
$orphanImage->delete();
|
64 |
+
}
|
65 |
+
}
|
66 |
+
|
67 |
public function configAction()
|
68 |
{
|
69 |
$this->_redirect("*/system_config/edit/section/cloudinary/");
|
app/code/community/Cloudinary/Cloudinary/etc/config.xml
CHANGED
@@ -2,7 +2,7 @@
|
|
2 |
<config>
|
3 |
<modules>
|
4 |
<Cloudinary_Cloudinary>
|
5 |
-
<version>2.
|
6 |
</Cloudinary_Cloudinary>
|
7 |
</modules>
|
8 |
<global>
|
2 |
<config>
|
3 |
<modules>
|
4 |
<Cloudinary_Cloudinary>
|
5 |
+
<version>2.2.0</version>
|
6 |
</Cloudinary_Cloudinary>
|
7 |
</modules>
|
8 |
<global>
|
lib/CloudinaryExtension/CloudinaryImageManager.php
CHANGED
@@ -1,12 +1,21 @@
|
|
1 |
<?php
|
|
|
2 |
namespace CloudinaryExtension;
|
3 |
|
|
|
|
|
|
|
4 |
/**
|
5 |
* Class CloudinaryImageManager
|
6 |
* @package CloudinaryExtension
|
7 |
*/
|
8 |
class CloudinaryImageManager
|
9 |
{
|
|
|
|
|
|
|
|
|
|
|
10 |
/**
|
11 |
* @var ImageProvider
|
12 |
*/
|
@@ -33,12 +42,29 @@ class CloudinaryImageManager
|
|
33 |
|
34 |
/**
|
35 |
* @param Image $image
|
|
|
|
|
36 |
*/
|
37 |
-
public function uploadAndSynchronise(Image $image)
|
38 |
{
|
39 |
-
|
40 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
41 |
|
|
|
42 |
}
|
43 |
|
44 |
/**
|
@@ -49,4 +75,15 @@ class CloudinaryImageManager
|
|
49 |
$this->cloudinaryImageProvider->delete($image);
|
50 |
$this->synchronisationRepository->removeSynchronised($image->getRelativePath());
|
51 |
}
|
52 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
<?php
|
2 |
+
|
3 |
namespace CloudinaryExtension;
|
4 |
|
5 |
+
use CloudinaryExtension\Exception\FileExists;
|
6 |
+
use Symfony\Component\Console\Output\OutputInterface;
|
7 |
+
|
8 |
/**
|
9 |
* Class CloudinaryImageManager
|
10 |
* @package CloudinaryExtension
|
11 |
*/
|
12 |
class CloudinaryImageManager
|
13 |
{
|
14 |
+
const MESSAGE_UPLOADING_IMAGE = 'Uploading image: %s';
|
15 |
+
const MESSAGE_UPLOADED_EXISTS = 'Image exists - marked as synchronised: %s';
|
16 |
+
const MESSAGE_RETRY = 'Failed with error: %s - attempting retry %d';
|
17 |
+
const MAXIMUM_RETRY_ATTEMPTS = 3;
|
18 |
+
|
19 |
/**
|
20 |
* @var ImageProvider
|
21 |
*/
|
42 |
|
43 |
/**
|
44 |
* @param Image $image
|
45 |
+
* @param OutputInterface|null $output
|
46 |
+
* @throws \Exception
|
47 |
*/
|
48 |
+
public function uploadAndSynchronise(Image $image, OutputInterface $output = null, $retryAttempt = 0)
|
49 |
{
|
50 |
+
try {
|
51 |
+
$this->report($output, sprintf(self::MESSAGE_UPLOADING_IMAGE, $image));
|
52 |
+
$this->cloudinaryImageProvider->upload($image);
|
53 |
+
} catch (FileExists $e) {
|
54 |
+
$this->report($output, sprintf(self::MESSAGE_UPLOADED_EXISTS, $image));
|
55 |
+
} catch (\Exception $e) {
|
56 |
+
if ($retryAttempt < self::MAXIMUM_RETRY_ATTEMPTS) {
|
57 |
+
$retryAttempt++;
|
58 |
+
$this->report($output, sprintf(self::MESSAGE_RETRY, $e->getMessage(), $retryAttempt));
|
59 |
+
usleep(rand(10, 1000) * 1000);
|
60 |
+
$this->uploadAndSynchronise($image, $output, $retryAttempt);
|
61 |
+
return;
|
62 |
+
}
|
63 |
+
|
64 |
+
throw $e;
|
65 |
+
}
|
66 |
|
67 |
+
$this->synchronisationRepository->saveAsSynchronized($image->getRelativePath());
|
68 |
}
|
69 |
|
70 |
/**
|
75 |
$this->cloudinaryImageProvider->delete($image);
|
76 |
$this->synchronisationRepository->removeSynchronised($image->getRelativePath());
|
77 |
}
|
78 |
+
|
79 |
+
/**
|
80 |
+
* @param OutputInterface|null $output
|
81 |
+
* @param string $message
|
82 |
+
*/
|
83 |
+
private function report(OutputInterface $output = null, $message = '')
|
84 |
+
{
|
85 |
+
if ($output) {
|
86 |
+
$output->writeln($message);
|
87 |
+
}
|
88 |
+
}
|
89 |
+
}
|
lib/CloudinaryExtension/CloudinaryImageProvider.php
CHANGED
@@ -5,8 +5,7 @@ namespace CloudinaryExtension;
|
|
5 |
|
6 |
use Cloudinary;
|
7 |
use Cloudinary\Uploader;
|
8 |
-
use CloudinaryExtension\Exception\
|
9 |
-
use CloudinaryExtension\Exception\MigrationError;
|
10 |
use CloudinaryExtension\Image\Transformation;
|
11 |
use CloudinaryExtension\Security;
|
12 |
use CloudinaryExtension\Image\Transformation\Format;
|
@@ -52,17 +51,18 @@ class CloudinaryImageProvider implements ImageProvider
|
|
52 |
|
53 |
public function upload(Image $image)
|
54 |
{
|
|
|
|
|
55 |
try {
|
56 |
$uploadResult = Uploader::upload(
|
57 |
(string)$image,
|
58 |
$this->configuration->getUploadConfig()->toArray() + [ "folder" => $image->getRelativeFolder()]
|
59 |
);
|
60 |
-
|
61 |
-
return $this->uploadResponseValidator->validateResponse($image, $uploadResult);
|
62 |
-
|
63 |
} catch (\Exception $e) {
|
64 |
-
|
65 |
}
|
|
|
|
|
66 |
}
|
67 |
|
68 |
public function retrieveTransformed(Image $image, Transformation $transformation)
|
@@ -80,7 +80,7 @@ class CloudinaryImageProvider implements ImageProvider
|
|
80 |
|
81 |
public function delete(Image $image)
|
82 |
{
|
83 |
-
Uploader::destroy($image->
|
84 |
}
|
85 |
|
86 |
public function validateCredentials()
|
@@ -93,4 +93,4 @@ class CloudinaryImageProvider implements ImageProvider
|
|
93 |
Cloudinary::config($this->configurationBuilder->build());
|
94 |
Cloudinary::$USER_PLATFORM = $this->configuration->getUserPlatform();
|
95 |
}
|
96 |
-
}
|
5 |
|
6 |
use Cloudinary;
|
7 |
use Cloudinary\Uploader;
|
8 |
+
use CloudinaryExtension\Exception\ApiError;
|
|
|
9 |
use CloudinaryExtension\Image\Transformation;
|
10 |
use CloudinaryExtension\Security;
|
11 |
use CloudinaryExtension\Image\Transformation\Format;
|
51 |
|
52 |
public function upload(Image $image)
|
53 |
{
|
54 |
+
$uploadResult = null;
|
55 |
+
|
56 |
try {
|
57 |
$uploadResult = Uploader::upload(
|
58 |
(string)$image,
|
59 |
$this->configuration->getUploadConfig()->toArray() + [ "folder" => $image->getRelativeFolder()]
|
60 |
);
|
|
|
|
|
|
|
61 |
} catch (\Exception $e) {
|
62 |
+
ApiError::throwWith($image, $e->getMessage());
|
63 |
}
|
64 |
+
|
65 |
+
return $this->uploadResponseValidator->validateResponse($image, $uploadResult);
|
66 |
}
|
67 |
|
68 |
public function retrieveTransformed(Image $image, Transformation $transformation)
|
80 |
|
81 |
public function delete(Image $image)
|
82 |
{
|
83 |
+
Uploader::destroy($image->getIdWithoutExtension());
|
84 |
}
|
85 |
|
86 |
public function validateCredentials()
|
93 |
Cloudinary::config($this->configurationBuilder->build());
|
94 |
Cloudinary::$USER_PLATFORM = $this->configuration->getUserPlatform();
|
95 |
}
|
96 |
+
}
|
lib/CloudinaryExtension/Exception/ApiError.php
ADDED
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace CloudinaryExtension\Exception;
|
4 |
+
|
5 |
+
class ApiError extends MigrationError
|
6 |
+
{
|
7 |
+
const DEFAULT_MESSAGE = 'Internal API error';
|
8 |
+
}
|
lib/CloudinaryExtension/Exception/FileExists.php
ADDED
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace CloudinaryExtension\Exception;
|
4 |
+
|
5 |
+
class FileExists extends MigrationError
|
6 |
+
{
|
7 |
+
const DEFAULT_MESSAGE = 'File already exists (cloudinary is case insensitive!!).';
|
8 |
+
}
|
lib/CloudinaryExtension/Exception/MigrationError.php
CHANGED
@@ -11,16 +11,21 @@ use Exception;
|
|
11 |
*/
|
12 |
class MigrationError extends Exception
|
13 |
{
|
14 |
-
const
|
15 |
-
const CODE_API_ERROR = 1;
|
16 |
-
|
17 |
-
private static $messages = [
|
18 |
-
self::CODE_FILE_ALREADY_EXISTS => 'File already exists (cloudinary is case insensitive!!).',
|
19 |
-
self::CODE_API_ERROR => 'Internal API error'
|
20 |
-
];
|
21 |
|
|
|
|
|
|
|
22 |
private $image;
|
23 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
24 |
/**
|
25 |
* @return Image
|
26 |
*/
|
@@ -31,20 +36,13 @@ class MigrationError extends Exception
|
|
31 |
|
32 |
/**
|
33 |
* @param Image $image
|
34 |
-
* @param $
|
35 |
-
* @
|
36 |
-
* @return MigrationError
|
37 |
*/
|
38 |
-
|
39 |
-
{
|
40 |
-
$result = new MigrationError($message ?: self::$messages[$code], $code);
|
41 |
-
$result->image = $image;
|
42 |
-
return $result;
|
43 |
-
}
|
44 |
-
|
45 |
-
public static function throwWith(Image $image, $code, $message = '')
|
46 |
{
|
47 |
-
|
|
|
|
|
48 |
}
|
49 |
-
|
50 |
}
|
11 |
*/
|
12 |
class MigrationError extends Exception
|
13 |
{
|
14 |
+
const DEFAULT_MESSAGE = 'Unknown error';
|
|
|
|
|
|
|
|
|
|
|
|
|
15 |
|
16 |
+
/**
|
17 |
+
* @var Image
|
18 |
+
*/
|
19 |
private $image;
|
20 |
|
21 |
+
/**
|
22 |
+
* @param string $suffix
|
23 |
+
*/
|
24 |
+
public function suffixMessage($suffix)
|
25 |
+
{
|
26 |
+
$this->message = sprintf('%s%s', $this->message, $suffix);
|
27 |
+
}
|
28 |
+
|
29 |
/**
|
30 |
* @return Image
|
31 |
*/
|
36 |
|
37 |
/**
|
38 |
* @param Image $image
|
39 |
+
* @param string $message
|
40 |
+
* @throws MigrationError
|
|
|
41 |
*/
|
42 |
+
public static function throwWith(Image $image, $message = '')
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
43 |
{
|
44 |
+
$exception = new static($message ?: static::DEFAULT_MESSAGE);
|
45 |
+
$exception->image = $image;
|
46 |
+
throw $exception;
|
47 |
}
|
|
|
48 |
}
|
lib/CloudinaryExtension/Image.php
CHANGED
@@ -40,11 +40,20 @@ class Image implements ImageInterface
|
|
40 |
|
41 |
public function getId()
|
42 |
{
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
48 |
}
|
49 |
|
50 |
public function getExtension()
|
40 |
|
41 |
public function getId()
|
42 |
{
|
43 |
+
return sprintf(
|
44 |
+
'%s%s',
|
45 |
+
$this->relativePath ? ($this->getRelativeFolder() . DIRECTORY_SEPARATOR) : '',
|
46 |
+
$this->pathInfo['basename']
|
47 |
+
);
|
48 |
+
}
|
49 |
+
|
50 |
+
public function getIdWithoutExtension()
|
51 |
+
{
|
52 |
+
return sprintf(
|
53 |
+
'%s%s',
|
54 |
+
$this->relativePath ? ($this->getRelativeFolder() . DIRECTORY_SEPARATOR) : '',
|
55 |
+
$this->pathInfo['filename']
|
56 |
+
);
|
57 |
}
|
58 |
|
59 |
public function getExtension()
|
lib/CloudinaryExtension/Image/Transformation.php
CHANGED
@@ -17,17 +17,12 @@ class Transformation
|
|
17 |
private $crop;
|
18 |
private $fetchFormat;
|
19 |
private $quality;
|
20 |
-
private $format;
|
21 |
private $dpr;
|
22 |
-
private $validFormats;
|
23 |
private $flags;
|
24 |
|
25 |
public function __construct()
|
26 |
{
|
27 |
-
$this->fetchFormat = FetchFormat::fromString(Format::FETCH_FORMAT_AUTO);
|
28 |
$this->crop = 'pad';
|
29 |
-
$this->format = Format::fromExtension('jpg');
|
30 |
-
$this->validFormats = array('gif', 'jpg', 'png', 'svg', 'webp');
|
31 |
$this->flags = [];
|
32 |
}
|
33 |
|
@@ -56,21 +51,6 @@ class Transformation
|
|
56 |
return $this;
|
57 |
}
|
58 |
|
59 |
-
public function withFormat(Format $format)
|
60 |
-
{
|
61 |
-
if (in_array((string)$format, $this->validFormats)) {
|
62 |
-
$this->format = $format;
|
63 |
-
}
|
64 |
-
|
65 |
-
return $this;
|
66 |
-
}
|
67 |
-
|
68 |
-
public function withoutFormat()
|
69 |
-
{
|
70 |
-
$this->format = null;
|
71 |
-
return $this;
|
72 |
-
}
|
73 |
-
|
74 |
public function withQuality(Quality $quality)
|
75 |
{
|
76 |
$this->quality = $quality;
|
@@ -83,11 +63,6 @@ class Transformation
|
|
83 |
return $this;
|
84 |
}
|
85 |
|
86 |
-
public function withOptimisationDisabled()
|
87 |
-
{
|
88 |
-
return $this->withFetchFormat(FetchFormat::fromString(''));
|
89 |
-
}
|
90 |
-
|
91 |
public function addFlags(array $flags = [])
|
92 |
{
|
93 |
$this->flags += $flags;
|
@@ -108,7 +83,6 @@ class Transformation
|
|
108 |
'gravity' => (string)$this->gravity ?: null,
|
109 |
'width' => $this->dimensions ? $this->dimensions->getWidth() : null,
|
110 |
'height' => $this->dimensions ? $this->dimensions->getHeight() : null,
|
111 |
-
'format' => (string)$this->format,
|
112 |
'dpr' => (string)$this->dpr,
|
113 |
'flags' => $this->flags
|
114 |
);
|
17 |
private $crop;
|
18 |
private $fetchFormat;
|
19 |
private $quality;
|
|
|
20 |
private $dpr;
|
|
|
21 |
private $flags;
|
22 |
|
23 |
public function __construct()
|
24 |
{
|
|
|
25 |
$this->crop = 'pad';
|
|
|
|
|
26 |
$this->flags = [];
|
27 |
}
|
28 |
|
51 |
return $this;
|
52 |
}
|
53 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
54 |
public function withQuality(Quality $quality)
|
55 |
{
|
56 |
$this->quality = $quality;
|
63 |
return $this;
|
64 |
}
|
65 |
|
|
|
|
|
|
|
|
|
|
|
66 |
public function addFlags(array $flags = [])
|
67 |
{
|
68 |
$this->flags += $flags;
|
83 |
'gravity' => (string)$this->gravity ?: null,
|
84 |
'width' => $this->dimensions ? $this->dimensions->getWidth() : null,
|
85 |
'height' => $this->dimensions ? $this->dimensions->getHeight() : null,
|
|
|
86 |
'dpr' => (string)$this->dpr,
|
87 |
'flags' => $this->flags
|
88 |
);
|
lib/CloudinaryExtension/Image/Transformation/FetchFormat.php
CHANGED
@@ -13,6 +13,11 @@ class FetchFormat
|
|
13 |
$this->value = $value;
|
14 |
}
|
15 |
|
|
|
|
|
|
|
|
|
|
|
16 |
public static function fromString($value)
|
17 |
{
|
18 |
return new FetchFormat($value);
|
13 |
$this->value = $value;
|
14 |
}
|
15 |
|
16 |
+
public static function auto()
|
17 |
+
{
|
18 |
+
return self::fromString(self::FETCH_FORMAT_AUTO);
|
19 |
+
}
|
20 |
+
|
21 |
public static function fromString($value)
|
22 |
{
|
23 |
return new FetchFormat($value);
|
lib/CloudinaryExtension/Image/Transformation/Format.php
DELETED
@@ -1,25 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
namespace CloudinaryExtension\Image\Transformation;
|
4 |
-
|
5 |
-
class Format
|
6 |
-
{
|
7 |
-
const FETCH_FORMAT_AUTO = 'auto';
|
8 |
-
|
9 |
-
private $value;
|
10 |
-
|
11 |
-
private function __construct($value)
|
12 |
-
{
|
13 |
-
$this->value = $value;
|
14 |
-
}
|
15 |
-
|
16 |
-
public static function fromExtension($value)
|
17 |
-
{
|
18 |
-
return new Format($value);
|
19 |
-
}
|
20 |
-
|
21 |
-
public function __toString()
|
22 |
-
{
|
23 |
-
return $this->value;
|
24 |
-
}
|
25 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
lib/CloudinaryExtension/Migration/BatchUploader.php
CHANGED
@@ -3,10 +3,10 @@
|
|
3 |
namespace CloudinaryExtension\Migration;
|
4 |
|
5 |
use CloudinaryExtension\Exception\MigrationError;
|
|
|
6 |
use CloudinaryExtension\Image;
|
7 |
use CloudinaryExtension\Image\Synchronizable;
|
8 |
use CloudinaryExtension\ImageProvider;
|
9 |
-
use \Cloudinary_Cloudinary_Helper_Util_ArrayUtils as ArrayUtils;
|
10 |
|
11 |
class BatchUploader
|
12 |
{
|
@@ -16,27 +16,70 @@ class BatchUploader
|
|
16 |
|
17 |
const MESSAGE_UPLOAD_ERROR = 'Cloudinary migration: %s trying to upload %s';
|
18 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
19 |
private $imageProvider;
|
20 |
|
|
|
|
|
|
|
21 |
private $baseMediaPath;
|
22 |
|
|
|
|
|
|
|
23 |
private $logger;
|
24 |
|
|
|
|
|
|
|
25 |
private $migrationTask;
|
26 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
27 |
private $countMigrated = 0;
|
28 |
-
private $countFailed = 0;
|
29 |
|
30 |
-
|
|
|
|
|
|
|
31 |
|
32 |
-
|
33 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
34 |
$this->imageProvider = $imageProvider;
|
35 |
$this->migrationTask = $migrationTask;
|
36 |
-
$this->baseMediaPath = $baseMediaPath;
|
37 |
$this->logger = $logger;
|
|
|
|
|
38 |
}
|
39 |
|
|
|
|
|
|
|
40 |
public function uploadImages(array $images)
|
41 |
{
|
42 |
$this->countMigrated = 0;
|
@@ -50,42 +93,87 @@ class BatchUploader
|
|
50 |
$this->logger->notice(sprintf(self::MESSAGE_STATUS, $this->countMigrated, $this->countFailed));
|
51 |
}
|
52 |
|
|
|
|
|
|
|
|
|
53 |
private function getAbsolutePath(Synchronizable $image)
|
54 |
{
|
55 |
return sprintf('%s%s', $this->baseMediaPath, $image->getFilename());
|
56 |
}
|
57 |
|
58 |
-
|
|
|
|
|
|
|
|
|
59 |
{
|
60 |
$absolutePath = $this->getAbsolutePath($image);
|
61 |
$relativePath = $image->getRelativePath();
|
|
|
62 |
$apiImage = Image::fromPath($absolutePath, $relativePath);
|
63 |
-
|
64 |
try {
|
65 |
$this->imageProvider->upload($apiImage);
|
66 |
$image->tagAsSynchronized();
|
67 |
$this->countMigrated++;
|
68 |
-
$this->logger->notice(sprintf(self::MESSAGE_UPLOADED, $
|
|
|
|
|
|
|
|
|
69 |
} catch (\Exception $e) {
|
70 |
-
$
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
71 |
$this->countFailed++;
|
72 |
-
$this->logger->error(
|
73 |
}
|
74 |
}
|
75 |
|
76 |
/**
|
77 |
-
* @
|
78 |
*/
|
79 |
-
|
80 |
{
|
81 |
-
|
|
|
82 |
}
|
83 |
|
84 |
-
|
|
|
|
|
|
|
|
|
|
|
85 |
{
|
86 |
-
|
87 |
-
|
88 |
-
}
|
|
|
|
|
|
|
89 |
}
|
90 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
91 |
}
|
3 |
namespace CloudinaryExtension\Migration;
|
4 |
|
5 |
use CloudinaryExtension\Exception\MigrationError;
|
6 |
+
use CloudinaryExtension\Exception\FileExists;
|
7 |
use CloudinaryExtension\Image;
|
8 |
use CloudinaryExtension\Image\Synchronizable;
|
9 |
use CloudinaryExtension\ImageProvider;
|
|
|
10 |
|
11 |
class BatchUploader
|
12 |
{
|
16 |
|
17 |
const MESSAGE_UPLOAD_ERROR = 'Cloudinary migration: %s trying to upload %s';
|
18 |
|
19 |
+
const MAXIMUM_RETRY_ATTEMPTS = 3;
|
20 |
+
|
21 |
+
const MESSAGE_UPLOADED_EXISTS = 'Cloudinary migration: %s exists - tagged as synchronized';
|
22 |
+
|
23 |
+
/**
|
24 |
+
* @var ImageProvider
|
25 |
+
*/
|
26 |
private $imageProvider;
|
27 |
|
28 |
+
/**
|
29 |
+
* @var string
|
30 |
+
*/
|
31 |
private $baseMediaPath;
|
32 |
|
33 |
+
/**
|
34 |
+
* @var Logger
|
35 |
+
*/
|
36 |
private $logger;
|
37 |
|
38 |
+
/**
|
39 |
+
* @var Task
|
40 |
+
*/
|
41 |
private $migrationTask;
|
42 |
|
43 |
+
/**
|
44 |
+
* @var callable
|
45 |
+
*/
|
46 |
+
private $exceptionCallback;
|
47 |
+
|
48 |
+
/**
|
49 |
+
* @var int
|
50 |
+
*/
|
51 |
private $countMigrated = 0;
|
|
|
52 |
|
53 |
+
/**
|
54 |
+
* @var int
|
55 |
+
*/
|
56 |
+
private $countFailed = 0;
|
57 |
|
58 |
+
/**
|
59 |
+
* BatchUploader constructor.
|
60 |
+
* @param ImageProvider $imageProvider
|
61 |
+
* @param Task $migrationTask
|
62 |
+
* @param Logger $logger
|
63 |
+
* @param string $baseMediaPath
|
64 |
+
* @param callable $exceptionCallback
|
65 |
+
*/
|
66 |
+
public function __construct(
|
67 |
+
ImageProvider $imageProvider,
|
68 |
+
Task $migrationTask,
|
69 |
+
Logger $logger,
|
70 |
+
$baseMediaPath,
|
71 |
+
callable $exceptionCallback
|
72 |
+
) {
|
73 |
$this->imageProvider = $imageProvider;
|
74 |
$this->migrationTask = $migrationTask;
|
|
|
75 |
$this->logger = $logger;
|
76 |
+
$this->baseMediaPath = $baseMediaPath;
|
77 |
+
$this->exceptionCallback = $exceptionCallback;
|
78 |
}
|
79 |
|
80 |
+
/**
|
81 |
+
* @param [Image]
|
82 |
+
*/
|
83 |
public function uploadImages(array $images)
|
84 |
{
|
85 |
$this->countMigrated = 0;
|
93 |
$this->logger->notice(sprintf(self::MESSAGE_STATUS, $this->countMigrated, $this->countFailed));
|
94 |
}
|
95 |
|
96 |
+
/**
|
97 |
+
* @param Synchronizable $image
|
98 |
+
* @return string
|
99 |
+
*/
|
100 |
private function getAbsolutePath(Synchronizable $image)
|
101 |
{
|
102 |
return sprintf('%s%s', $this->baseMediaPath, $image->getFilename());
|
103 |
}
|
104 |
|
105 |
+
/**
|
106 |
+
* @param Synchronizable $image
|
107 |
+
* @param int $retryAttempt
|
108 |
+
*/
|
109 |
+
private function uploadImage(Synchronizable $image, $retryAttempt = 0)
|
110 |
{
|
111 |
$absolutePath = $this->getAbsolutePath($image);
|
112 |
$relativePath = $image->getRelativePath();
|
113 |
+
$pathDescription = sprintf('%s - %s', $absolutePath, $relativePath);
|
114 |
$apiImage = Image::fromPath($absolutePath, $relativePath);
|
|
|
115 |
try {
|
116 |
$this->imageProvider->upload($apiImage);
|
117 |
$image->tagAsSynchronized();
|
118 |
$this->countMigrated++;
|
119 |
+
$this->logger->notice(sprintf(self::MESSAGE_UPLOADED, $pathDescription));
|
120 |
+
} catch (FileExists $e) {
|
121 |
+
$image->tagAsSynchronized();
|
122 |
+
$this->countMigrated++;
|
123 |
+
$this->logger->notice(sprintf(self::MESSAGE_UPLOADED_EXISTS, $image->getFilename()));
|
124 |
} catch (\Exception $e) {
|
125 |
+
if ($retryAttempt < self::MAXIMUM_RETRY_ATTEMPTS) {
|
126 |
+
$retryAttempt++;
|
127 |
+
$retryMessage = sprintf(' - attempting retry %d', $retryAttempt);
|
128 |
+
$this->notify($this->addRetryMessage($retryMessage, $e));
|
129 |
+
$this->logger->error($this->buildUploadErrorMessage($e, $pathDescription . $retryMessage));
|
130 |
+
usleep(rand(10, 1000) * 1000);
|
131 |
+
$this->uploadImage($image, $retryAttempt);
|
132 |
+
return;
|
133 |
+
}
|
134 |
+
|
135 |
+
$retryMessage = sprintf('- failed after %d retry attempts', $retryAttempt);
|
136 |
+
$this->notify($this->addRetryMessage($retryMessage, $e));
|
137 |
$this->countFailed++;
|
138 |
+
$this->logger->error($this->buildUploadErrorMessage($e, $pathDescription . $retryMessage));
|
139 |
}
|
140 |
}
|
141 |
|
142 |
/**
|
143 |
+
* @param \Exception $e
|
144 |
*/
|
145 |
+
private function notify(\Exception $e)
|
146 |
{
|
147 |
+
$callback = $this->exceptionCallback;
|
148 |
+
$callback($e);
|
149 |
}
|
150 |
|
151 |
+
/**
|
152 |
+
* @param $retryMessage
|
153 |
+
* @param \Exception $e
|
154 |
+
* @return \Exception
|
155 |
+
*/
|
156 |
+
private function addRetryMessage($retryMessage, \Exception $e)
|
157 |
{
|
158 |
+
if ($e instanceof MigrationError) {
|
159 |
+
$e->suffixMessage($retryMessage);
|
160 |
+
} else {
|
161 |
+
$e = new \Exception($e->getMessage() . $retryMessage);
|
162 |
+
}
|
163 |
+
return $e;
|
164 |
}
|
165 |
|
166 |
+
/**
|
167 |
+
* @param \Exception $e
|
168 |
+
* @param $message
|
169 |
+
* @return string
|
170 |
+
*/
|
171 |
+
private function buildUploadErrorMessage(\Exception $e, $message)
|
172 |
+
{
|
173 |
+
return sprintf(
|
174 |
+
self::MESSAGE_UPLOAD_ERROR,
|
175 |
+
$e->getMessage(),
|
176 |
+
$message
|
177 |
+
);
|
178 |
+
}
|
179 |
}
|
lib/CloudinaryExtension/Migration/SynchronizedMediaRepository.php
CHANGED
@@ -5,4 +5,5 @@ namespace CloudinaryExtension\Migration;
|
|
5 |
interface SynchronizedMediaRepository
|
6 |
{
|
7 |
public function findUnsynchronisedImages();
|
|
|
8 |
}
|
5 |
interface SynchronizedMediaRepository
|
6 |
{
|
7 |
public function findUnsynchronisedImages();
|
8 |
+
public function findOrphanedSynchronisedImages();
|
9 |
}
|
lib/CloudinaryExtension/UploadResponseValidator.php
CHANGED
@@ -2,14 +2,14 @@
|
|
2 |
|
3 |
namespace CloudinaryExtension;
|
4 |
|
5 |
-
use CloudinaryExtension\Exception\
|
6 |
|
7 |
class UploadResponseValidator
|
8 |
{
|
9 |
public function validateResponse($image, $uploadResponse)
|
10 |
{
|
11 |
if ($uploadResponse['existing'] == 1) {
|
12 |
-
|
13 |
}
|
14 |
|
15 |
return $uploadResponse;
|
2 |
|
3 |
namespace CloudinaryExtension;
|
4 |
|
5 |
+
use CloudinaryExtension\Exception\FileExists;
|
6 |
|
7 |
class UploadResponseValidator
|
8 |
{
|
9 |
public function validateResponse($image, $uploadResponse)
|
10 |
{
|
11 |
if ($uploadResponse['existing'] == 1) {
|
12 |
+
FileExists::throwWith($image);
|
13 |
}
|
14 |
|
15 |
return $uploadResponse;
|
lib/CloudinaryExtension/UrlGenerator.php
CHANGED
@@ -41,13 +41,10 @@ class UrlGenerator
|
|
41 |
return (string)$image;
|
42 |
}
|
43 |
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
}
|
49 |
-
|
50 |
-
return (string)$this->imageProvider->retrieveTransformed($image, $transformation);
|
51 |
}
|
52 |
|
53 |
/**
|
@@ -58,7 +55,7 @@ class UrlGenerator
|
|
58 |
*/
|
59 |
public function generateWithDimensions(ImageInterface $image, Dimensions $dimensions)
|
60 |
{
|
61 |
-
$transformation =
|
62 |
|
63 |
return $this->generateFor($image, $transformation->withDimensions($dimensions));
|
64 |
}
|
41 |
return (string)$image;
|
42 |
}
|
43 |
|
44 |
+
return (string)$this->imageProvider->retrieveTransformed(
|
45 |
+
$image,
|
46 |
+
$transformation ?: $this->configuration->getDefaultTransformation()
|
47 |
+
);
|
|
|
|
|
|
|
48 |
}
|
49 |
|
50 |
/**
|
55 |
*/
|
56 |
public function generateWithDimensions(ImageInterface $image, Dimensions $dimensions)
|
57 |
{
|
58 |
+
$transformation = $this->configuration->getDefaultTransformation();
|
59 |
|
60 |
return $this->generateFor($image, $transformation->withDimensions($dimensions));
|
61 |
}
|
package.xml
CHANGED
@@ -1,22 +1,23 @@
|
|
1 |
<?xml version="1.0"?>
|
2 |
<package>
|
3 |
<name>Cloudinary_Cloudinary</name>
|
4 |
-
<version>2.
|
5 |
<stability>stable</stability>
|
6 |
<license>MIT License (MITL)</license>
|
7 |
<channel>community</channel>
|
8 |
<extends/>
|
9 |
<summary>Cloudinary - Image Management In The Cloud</summary>
|
10 |
<description>Cloudinary supercharges your images! Upload images to the cloud, deliver optimized via a fast CDN, perform smart resizing and apply effects.</description>
|
11 |
-
<notes>
|
12 |
-

|
13 |
-
|
14 |
-

|
15 |
-
|
|
|
16 |
<authors><author><name>Cloudinary</name><user>cloudinary</user><email>accounts+magento@cloudinary.com</email></author></authors>
|
17 |
-
<date>2017-04
|
18 |
-
<time>
|
19 |
-
<contents><target name="magecommunity"><dir name="Cloudinary"><dir name="Cloudinary"><dir name="Block"><dir name="Adminhtml"><dir name="Manage"><file name="Grid.php" hash="b6a05f6ba08c5ba0d08846a7b0a06776"/></dir><file name="Manage.php" hash="9cd8997737c1191cff57dc8530daa26c"/><dir name="Page"><file name="Menu.php" hash="891d6a4c075ba03c9a20658076c86ad0"/></dir><dir name="System"><dir name="Config"><file name="Signup.php" hash="ed6accbe7a4ce16bb0679eaf0c2dbb22"/></dir></dir></dir></dir><dir name="Helper"><file name="Autoloader.php" hash="393b3e2fc25e63ca28157152d2542b18"/><file name="Console.php" hash="7c909e3226c51c05d6da1f6ff9cbbfc9"/><file name="Cron.php" hash="805557370a2006b15444b7a62bbbc65a"/><file name="Data.php" hash="42c9d44f1bbe530e30cf5379846dea65"/><file name="Image.php" hash="af1c1d734793d6b08feaa7e1abd591d0"/></dir><dir name="Model"><dir name="Catalog"><dir name="Product"><file name="Image.php" hash="b5d14bcb836158890152c9fed191f8bc"/><dir name="Media"><file name="Config.php" hash="c2dbac447d4a22c920c19b0d4eb2672e"/></dir><file name="Media.php" hash="05726616a07d7d08933e9654e6107283"/></dir></dir><dir name="Cms"><dir name="Adminhtml"><dir name="Template"><file name="Filter.php" hash="792893f6b4e884a8e42847d457a6068c"/></dir></dir><file name="Synchronisation.php" hash="8d830a18f169a0ff5f7d865e3afcb710"/><dir name="Template"><file name="Filter.php" hash="c3fe64f98128043de13e92156a26ab02"/></dir><file name="Uploader.php" hash="021195c01a7e6fd9e72c5a30ebd11554"/><dir name="Wysiwyg"><dir name="Images"><file name="Storage.php" hash="0d23e557d6db06308886d9307fe92665"/></dir></dir></dir><file name="CollectionCounter.php" hash="e69953aee5d966a3ec13d33533f017e0"/><file name="Configuration.php" hash="fa6fb95c166048005143bc52d85933f9"/><file name="Cron.php" hash="
|
20 |
<compatible/>
|
21 |
<dependencies><required><php><min>5.4.0</min><max>7.1.0</max></php></required></dependencies>
|
22 |
</package>
|
1 |
<?xml version="1.0"?>
|
2 |
<package>
|
3 |
<name>Cloudinary_Cloudinary</name>
|
4 |
+
<version>2.2.0</version>
|
5 |
<stability>stable</stability>
|
6 |
<license>MIT License (MITL)</license>
|
7 |
<channel>community</channel>
|
8 |
<extends/>
|
9 |
<summary>Cloudinary - Image Management In The Cloud</summary>
|
10 |
<description>Cloudinary supercharges your images! Upload images to the cloud, deliver optimized via a fast CDN, perform smart resizing and apply effects.</description>
|
11 |
+
<notes> Release 2.2.0 notes:
|
12 |
+
- Existing images are not remigrated during migration, and do not fail migration
|
13 |
+
- Fix bug where migration status shows value above 100%
|
14 |
+
- Preserve original file extensions in Cloudinary image urls
|
15 |
+
- Retry migration when network failures occur
|
16 |
+
</notes>
|
17 |
<authors><author><name>Cloudinary</name><user>cloudinary</user><email>accounts+magento@cloudinary.com</email></author></authors>
|
18 |
+
<date>2017-05-04</date>
|
19 |
+
<time>07:33:31</time>
|
20 |
+
<contents><target name="magecommunity"><dir name="Cloudinary"><dir name="Cloudinary"><dir name="Block"><dir name="Adminhtml"><dir name="Manage"><file name="Grid.php" hash="b6a05f6ba08c5ba0d08846a7b0a06776"/></dir><file name="Manage.php" hash="9cd8997737c1191cff57dc8530daa26c"/><dir name="Page"><file name="Menu.php" hash="891d6a4c075ba03c9a20658076c86ad0"/></dir><dir name="System"><dir name="Config"><file name="Signup.php" hash="ed6accbe7a4ce16bb0679eaf0c2dbb22"/></dir></dir></dir></dir><dir name="Helper"><file name="Autoloader.php" hash="393b3e2fc25e63ca28157152d2542b18"/><file name="Console.php" hash="7c909e3226c51c05d6da1f6ff9cbbfc9"/><file name="Cron.php" hash="805557370a2006b15444b7a62bbbc65a"/><file name="Data.php" hash="42c9d44f1bbe530e30cf5379846dea65"/><file name="Image.php" hash="af1c1d734793d6b08feaa7e1abd591d0"/></dir><dir name="Model"><dir name="Catalog"><dir name="Product"><file name="Image.php" hash="b5d14bcb836158890152c9fed191f8bc"/><dir name="Media"><file name="Config.php" hash="c2dbac447d4a22c920c19b0d4eb2672e"/></dir><file name="Media.php" hash="05726616a07d7d08933e9654e6107283"/></dir></dir><dir name="Cms"><dir name="Adminhtml"><dir name="Template"><file name="Filter.php" hash="792893f6b4e884a8e42847d457a6068c"/></dir></dir><file name="Synchronisation.php" hash="8d830a18f169a0ff5f7d865e3afcb710"/><dir name="Template"><file name="Filter.php" hash="c3fe64f98128043de13e92156a26ab02"/></dir><file name="Uploader.php" hash="021195c01a7e6fd9e72c5a30ebd11554"/><dir name="Wysiwyg"><dir name="Images"><file name="Storage.php" hash="0d23e557d6db06308886d9307fe92665"/></dir></dir></dir><file name="CollectionCounter.php" hash="e69953aee5d966a3ec13d33533f017e0"/><file name="Configuration.php" hash="fa6fb95c166048005143bc52d85933f9"/><file name="Cron.php" hash="a7296d26862df0d382023d33496bb80a"/><dir name="Exception"><file name="BadFilePathException.php" hash="68135da8dfe2f0589a531b4bd36e3330"/></dir><file name="Image.php" hash="84d42417651e2feefdb1b0c048f61ca4"/><file name="Logger.php" hash="ab5e45b0769c9dbee33025a202a87fee"/><file name="MagentoFolderTranslator.php" hash="37219fc1804d6ad8d1686af8509e1963"/><file name="Migration.php" hash="30f671877307d93904fd823d01d35c1d"/><file name="MigrationError.php" hash="67eca6725679a5dae6eab65efae39c64"/><file name="Observer.php" hash="78fdf1b2d98864f2aa0538b5eb203275"/><dir name="Resource"><dir name="Cms"><dir name="Synchronisation"><file name="Collection.php" hash="226db91ad96a348f0d937781358f9dec"/></dir></dir><dir name="Media"><file name="Collection.php" hash="f54d914a6f79c7b3ab51f822bf64de39"/></dir><file name="Migration.php" hash="69a545d0627016afc03ea097641aa749"/><dir name="MigrationError"><file name="Collection.php" hash="3c5ef530b18b4cd7763a610b84cd3d41"/></dir><file name="MigrationError.php" hash="e6de24a80cb0daed6ead44c699dce535"/><dir name="Synchronisation"><file name="Collection.php" hash="d16275121feb30e57b9b54122e26f05c"/></dir><file name="Synchronisation.php" hash="5b721d854d8f89bc3310e46081be7153"/></dir><file name="Synchronisation.php" hash="05414c5959efc7656b8e101617005d9a"/><file name="SynchronisedMediaUnifier.php" hash="899abd4ef47be0ce3604cfc8790c582a"/><file name="SynchronizationChecker.php" hash="fd2a1fd763b7f5b895a392b48e209f00"/><dir name="System"><dir name="Config"><dir name="Source"><dir name="Dropdown"><file name="Dpr.php" hash="2b9bfd5f836dbdb5d7224d298264f540"/><file name="Gravity.php" hash="c241498e2093640892170673cd7550cd"/><file name="Quality.php" hash="e0c5902f5c36c96fb8a8ba7cc741ce1f"/></dir></dir></dir></dir></dir><dir name="controllers"><dir name="Adminhtml"><file name="CloudinaryController.php" hash="d44f610256d0d7a5633a94977442787b"/></dir></dir><dir name="data"><dir name="cloudinary_setup"><file name="data-upgrade-0.1.0-0.1.1.php" hash="4c6ce6cd9ab0d94654afb4a398fb3d6c"/><file name="data-upgrade-1.1.2-1.1.3.php" hash="fe2026874346017303a8f41a9d0d6c0d"/></dir></dir><dir name="etc"><file name="adminhtml.xml" hash="46e365e2f4b1d543aad248dfcfb99c50"/><file name="config.xml" hash="109fe3a888071222230cbd8804fa8123"/><file name="system.xml" hash="a4ae810df3e6587625d395985b79ee83"/></dir><dir name="sql"><dir name="cloudinary_setup"><file name="install-0.1.0.php" hash="55d93b3dab573c2a932edbb5a2fa4865"/><file name="upgrade-0.1.0-0.1.1.php" hash="6c8d430fbf7b9714586b67db3d455008"/><file name="upgrade-1.1.3-1.1.4.php" hash="d6314fc1843b2061d0d04ae60c4d8091"/><file name="upgrade-1.1.4-1.1.5.php" hash="5b035e4b600cbbc743e9ff6a7b505230"/><file name="upgrade-1.1.5-1.1.6.php" hash="323c5e50635018be420cf524072f6a92"/><file name="upgrade-2.0.0-2.1.0.php" hash="9d053bed5099e064eed808a090755b03"/></dir></dir></dir></dir></target><target name="mageetc"><dir name="modules"><file name="Cloudinary_Cloudinary.xml" hash="9337962a4ccf8a43164d5d71dfd2d756"/></dir></target><target name="magelib"><dir name="CloudinaryExtension"><file name="Cloud.php" hash="59b0debf9ae297e4e824e39ba819b1d1"/><file name="CloudinaryImageManager.php" hash="94af20e7b144adc4a27ee011aabbefe3"/><file name="CloudinaryImageProvider.php" hash="c4199a5384e6c42316ab4c5c74ed35e3"/><file name="ConfigurationBuilder.php" hash="c8832b207d9228ef14b3c74100ee74c4"/><file name="ConfigurationInterface.php" hash="4129b1e282fb0000b78946f07baa740c"/><file name="CredentialValidator.php" hash="965b0bd024f668aabcc9f30ef2e3c240"/><file name="Credentials.php" hash="71054eb4af7b6496608ffd14912bdbe4"/><dir name="Exception"><file name="ApiError.php" hash="d6fb1e32ca96183e9800c3706de37206"/><file name="FileExists.php" hash="6969387c67deef15a378cb94b9d269ac"/><file name="InvalidCredentials.php" hash="abecc635a25f6c9896c605ad16e1f7d7"/><file name="MigrationError.php" hash="92ea7aa65f4e14e606fa107d33f3ad30"/></dir><file name="FolderTranslator.php" hash="19a335acf751d67bd7efe46829602490"/><dir name="Image"><file name="ImageFactory.php" hash="0a2e066331584d33a9c4ec03787fd6e5"/><file name="LocalImage.php" hash="ab9b814b1a006baf05b9904af3ebce74"/><file name="Synchronizable.php" hash="b842f71ed25718838233207b7748f1bf"/><file name="SynchronizationChecker.php" hash="f2c45545766a81fede68138cf84dd1af"/><dir name="Transformation"><file name="Crop.php" hash="84e57281780a57326c938ac776641e8b"/><file name="Dimensions.php" hash="86a36c564aa41a08da2cf383d611c060"/><file name="Dpr.php" hash="f78cd1bfabaf3088ca8d4af972bfd453"/><file name="FetchFormat.php" hash="c745a6d80b509755cb6ae9fe37b95d76"/><file name="Gravity.php" hash="c1c2adf4dbbeaa6b06d67d2014300559"/><file name="Quality.php" hash="23a857f3910aecf6e45645194ff7f54e"/></dir><file name="Transformation.php" hash="7037bb18dcf82ee729deb6a06344faab"/></dir><file name="Image.php" hash="3090cfbaa3b2a90b5ef4a2a94b165581"/><file name="ImageInterface.php" hash="4a7c7e39d7fda0b0fa99affcac78ec8c"/><file name="ImageProvider.php" hash="a615c472cdc8a6ad7d887133db35c262"/><dir name="Migration"><file name="BatchUploader.php" hash="87d9dcf1c07fb9975283d7e4f577f1b9"/><file name="Logger.php" hash="648b47bb065de0c81b386ac300b4f9a3"/><file name="Queue.php" hash="add92864192b0950c29c91ffe5e5a3ee"/><file name="SynchronizedMediaRepository.php" hash="6b4e07f253aad9b845c68d51a1ab4166"/><file name="Task.php" hash="ac11d06c531d48b38cf88f6e8f2bdc19"/></dir><dir name="Security"><file name="ApiSignature.php" hash="049c7db2684ec2a6cf5bb4efcd064951"/><file name="CloudinaryEnvironmentVariable.php" hash="418af61bdbcfef955df29ac47c54415b"/><file name="ConsoleUrl.php" hash="4e748cfe0f5a0aeab2307c623179c6f9"/><file name="EnvironmentVariable.php" hash="297fa60b819ffc028b9a32dae6eef63d"/><file name="Key.php" hash="ac3a50b59f2a7db1edcf30386759c7ec"/><file name="Secret.php" hash="b1010679976575d57752dbb07f1b94ed"/><file name="SignedConsoleUrl.php" hash="791e1f1080be23423c2ad87f431f6221"/></dir><file name="SynchroniseAssetsRepositoryInterface.php" hash="e0d8e270ae2c74214e82e53e04e3dc0f"/><file name="UploadConfig.php" hash="a68f1ea7b84574ec36a8d2fac9bd6054"/><file name="UploadResponseValidator.php" hash="2d20dba12898b277b20b010d24f18859"/><file name="UrlGenerator.php" hash="06d223e5628c68570a2af4f8fb2306ce"/><file name="ValidateRemoteUrlRequest.php" hash="c2e2eb712e5293ad508a23610dfbbd6d"/></dir><dir name="Cloudinary"><file name="Api.php" hash="d71322346c3625db7c3563cdad191e8c"/><file name="AuthToken.php" hash="bec8b856baf85d89a249c932c3eba39f"/><file name="Cloudinary.php" hash="f2ec7b7bc8fc7c978f7773c3d4ccc5dd"/><file name="CloudinaryField.php" hash="411714580d21b58115ab07737367173a"/><file name="Helpers.php" hash="4db8371fc84d34be49c8ea04eee7d6eb"/><file name="PreloadedFile.php" hash="73cc9e276f96553814f05eae592d11ee"/><file name="Uploader.php" hash="eae92a330d19654028a8d16410616421"/><file name="cacert.pem" hash="c4290b9deb70d0bef2f88b67fc68c8ec"/></dir></target><target name="magedesign"><dir name="adminhtml"><dir name="default"><dir name="default"><dir name="layout"><dir name="cloudinary"><file name="cloudinary.xml" hash="e5a2def3fccdb6a365364dcf23964d08"/></dir></dir><dir name="template"><dir name="cloudinary"><file name="manage.phtml" hash="7630d346f45d7118748b647be3501fa3"/><dir name="system"><dir name="config"><file name="signup.phtml" hash="2a0e06990eb542f22531ac2ebb5996f5"/></dir></dir></dir></dir></dir></dir></dir></target></contents>
|
21 |
<compatible/>
|
22 |
<dependencies><required><php><min>5.4.0</min><max>7.1.0</max></php></required></dependencies>
|
23 |
</package>
|