diff options
author | Jeremy Benoist <jeremy.benoist@gmail.com> | 2016-11-01 14:49:02 +0100 |
---|---|---|
committer | Jeremy Benoist <jeremy.benoist@gmail.com> | 2016-11-01 14:49:02 +0100 |
commit | e0597476d1d5f6a4a7d6ea9b76966465f3d22fb8 (patch) | |
tree | 65c1ffe6906e9faacca5cbbf814f762d9013551d | |
parent | aedd6ca0fd212abd07ec59c5fd58ea2ca99198c5 (diff) | |
download | wallabag-e0597476d1d5f6a4a7d6ea9b76966465f3d22fb8.tar.gz wallabag-e0597476d1d5f6a4a7d6ea9b76966465f3d22fb8.tar.zst wallabag-e0597476d1d5f6a4a7d6ea9b76966465f3d22fb8.zip |
Use custom event instead of Doctrine ones
This give us ability to use Entry ID to determine where to store images and it’s then more easy to remove them when we remove the entry.
8 files changed, 202 insertions, 126 deletions
diff --git a/src/Wallabag/CoreBundle/Controller/EntryController.php b/src/Wallabag/CoreBundle/Controller/EntryController.php index 97bb3d12..3f4eb17d 100644 --- a/src/Wallabag/CoreBundle/Controller/EntryController.php +++ b/src/Wallabag/CoreBundle/Controller/EntryController.php | |||
@@ -13,6 +13,8 @@ use Wallabag\CoreBundle\Form\Type\EntryFilterType; | |||
13 | use Wallabag\CoreBundle\Form\Type\EditEntryType; | 13 | use Wallabag\CoreBundle\Form\Type\EditEntryType; |
14 | use Wallabag\CoreBundle\Form\Type\NewEntryType; | 14 | use Wallabag\CoreBundle\Form\Type\NewEntryType; |
15 | use Sensio\Bundle\FrameworkExtraBundle\Configuration\Cache; | 15 | use Sensio\Bundle\FrameworkExtraBundle\Configuration\Cache; |
16 | use Wallabag\CoreBundle\Event\EntrySavedEvent; | ||
17 | use Wallabag\CoreBundle\Event\EntryDeletedEvent; | ||
16 | 18 | ||
17 | class EntryController extends Controller | 19 | class EntryController extends Controller |
18 | { | 20 | { |
@@ -81,6 +83,9 @@ class EntryController extends Controller | |||
81 | $em->persist($entry); | 83 | $em->persist($entry); |
82 | $em->flush(); | 84 | $em->flush(); |
83 | 85 | ||
86 | // entry saved, dispatch event about it! | ||
87 | $this->get('event_dispatcher')->dispatch(EntrySavedEvent::NAME, new EntrySavedEvent($entry)); | ||
88 | |||
84 | return $this->redirect($this->generateUrl('homepage')); | 89 | return $this->redirect($this->generateUrl('homepage')); |
85 | } | 90 | } |
86 | 91 | ||
@@ -107,6 +112,9 @@ class EntryController extends Controller | |||
107 | $em = $this->getDoctrine()->getManager(); | 112 | $em = $this->getDoctrine()->getManager(); |
108 | $em->persist($entry); | 113 | $em->persist($entry); |
109 | $em->flush(); | 114 | $em->flush(); |
115 | |||
116 | // entry saved, dispatch event about it! | ||
117 | $this->get('event_dispatcher')->dispatch(EntrySavedEvent::NAME, new EntrySavedEvent($entry)); | ||
110 | } | 118 | } |
111 | 119 | ||
112 | return $this->redirect($this->generateUrl('homepage')); | 120 | return $this->redirect($this->generateUrl('homepage')); |
@@ -343,6 +351,9 @@ class EntryController extends Controller | |||
343 | $em->persist($entry); | 351 | $em->persist($entry); |
344 | $em->flush(); | 352 | $em->flush(); |
345 | 353 | ||
354 | // entry saved, dispatch event about it! | ||
355 | $this->get('event_dispatcher')->dispatch(EntrySavedEvent::NAME, new EntrySavedEvent($entry)); | ||
356 | |||
346 | return $this->redirect($this->generateUrl('view', ['id' => $entry->getId()])); | 357 | return $this->redirect($this->generateUrl('view', ['id' => $entry->getId()])); |
347 | } | 358 | } |
348 | 359 | ||
@@ -431,6 +442,9 @@ class EntryController extends Controller | |||
431 | UrlGeneratorInterface::ABSOLUTE_PATH | 442 | UrlGeneratorInterface::ABSOLUTE_PATH |
432 | ); | 443 | ); |
433 | 444 | ||
445 | // entry deleted, dispatch event about it! | ||
446 | $this->get('event_dispatcher')->dispatch(EntryDeletedEvent::NAME, new EntryDeletedEvent($entry)); | ||
447 | |||
434 | $em = $this->getDoctrine()->getManager(); | 448 | $em = $this->getDoctrine()->getManager(); |
435 | $em->remove($entry); | 449 | $em->remove($entry); |
436 | $em->flush(); | 450 | $em->flush(); |
diff --git a/src/Wallabag/CoreBundle/Event/EntryDeletedEvent.php b/src/Wallabag/CoreBundle/Event/EntryDeletedEvent.php new file mode 100644 index 00000000..e9061d04 --- /dev/null +++ b/src/Wallabag/CoreBundle/Event/EntryDeletedEvent.php | |||
@@ -0,0 +1,26 @@ | |||
1 | <?php | ||
2 | |||
3 | namespace Wallabag\CoreBundle\Event; | ||
4 | |||
5 | use Symfony\Component\EventDispatcher\Event; | ||
6 | use Wallabag\CoreBundle\Entity\Entry; | ||
7 | |||
8 | /** | ||
9 | * This event is fired as soon as an entry is deleted. | ||
10 | */ | ||
11 | class EntryDeletedEvent extends Event | ||
12 | { | ||
13 | const NAME = 'entry.deleted'; | ||
14 | |||
15 | protected $entry; | ||
16 | |||
17 | public function __construct(Entry $entry) | ||
18 | { | ||
19 | $this->entry = $entry; | ||
20 | } | ||
21 | |||
22 | public function getEntry() | ||
23 | { | ||
24 | return $this->entry; | ||
25 | } | ||
26 | } | ||
diff --git a/src/Wallabag/CoreBundle/Event/EntrySavedEvent.php b/src/Wallabag/CoreBundle/Event/EntrySavedEvent.php new file mode 100644 index 00000000..5fdb5221 --- /dev/null +++ b/src/Wallabag/CoreBundle/Event/EntrySavedEvent.php | |||
@@ -0,0 +1,26 @@ | |||
1 | <?php | ||
2 | |||
3 | namespace Wallabag\CoreBundle\Event; | ||
4 | |||
5 | use Symfony\Component\EventDispatcher\Event; | ||
6 | use Wallabag\CoreBundle\Entity\Entry; | ||
7 | |||
8 | /** | ||
9 | * This event is fired as soon as an entry was saved. | ||
10 | */ | ||
11 | class EntrySavedEvent extends Event | ||
12 | { | ||
13 | const NAME = 'entry.saved'; | ||
14 | |||
15 | protected $entry; | ||
16 | |||
17 | public function __construct(Entry $entry) | ||
18 | { | ||
19 | $this->entry = $entry; | ||
20 | } | ||
21 | |||
22 | public function getEntry() | ||
23 | { | ||
24 | return $this->entry; | ||
25 | } | ||
26 | } | ||
diff --git a/src/Wallabag/CoreBundle/Event/Subscriber/DownloadImagesSubscriber.php b/src/Wallabag/CoreBundle/Event/Subscriber/DownloadImagesSubscriber.php index 6fddcea9..4ebe837b 100644 --- a/src/Wallabag/CoreBundle/Event/Subscriber/DownloadImagesSubscriber.php +++ b/src/Wallabag/CoreBundle/Event/Subscriber/DownloadImagesSubscriber.php | |||
@@ -2,110 +2,85 @@ | |||
2 | 2 | ||
3 | namespace Wallabag\CoreBundle\Event\Subscriber; | 3 | namespace Wallabag\CoreBundle\Event\Subscriber; |
4 | 4 | ||
5 | use Doctrine\Common\EventSubscriber; | 5 | use Symfony\Component\EventDispatcher\EventSubscriberInterface; |
6 | use Doctrine\ORM\Event\LifecycleEventArgs; | ||
7 | use Psr\Log\LoggerInterface; | 6 | use Psr\Log\LoggerInterface; |
8 | use Wallabag\CoreBundle\Helper\DownloadImages; | 7 | use Wallabag\CoreBundle\Helper\DownloadImages; |
9 | use Wallabag\CoreBundle\Entity\Entry; | 8 | use Wallabag\CoreBundle\Entity\Entry; |
9 | use Wallabag\CoreBundle\Event\EntrySavedEvent; | ||
10 | use Wallabag\CoreBundle\Event\EntryDeletedEvent; | ||
10 | use Doctrine\ORM\EntityManager; | 11 | use Doctrine\ORM\EntityManager; |
11 | use Craue\ConfigBundle\Util\Config; | ||
12 | 12 | ||
13 | class DownloadImagesSubscriber implements EventSubscriber | 13 | class DownloadImagesSubscriber implements EventSubscriberInterface |
14 | { | 14 | { |
15 | private $configClass; | 15 | private $em; |
16 | private $downloadImages; | 16 | private $downloadImages; |
17 | private $enabled; | ||
17 | private $logger; | 18 | private $logger; |
18 | 19 | ||
19 | /** | 20 | public function __construct(EntityManager $em, DownloadImages $downloadImages, $enabled, LoggerInterface $logger) |
20 | * We inject the class instead of the service otherwise it generates a circular reference with the EntityManager. | ||
21 | * So we build the service ourself when we got the EntityManager (in downloadImages). | ||
22 | */ | ||
23 | public function __construct(DownloadImages $downloadImages, $configClass, LoggerInterface $logger) | ||
24 | { | 21 | { |
22 | $this->em = $em; | ||
25 | $this->downloadImages = $downloadImages; | 23 | $this->downloadImages = $downloadImages; |
26 | $this->configClass = $configClass; | 24 | $this->enabled = $enabled; |
27 | $this->logger = $logger; | 25 | $this->logger = $logger; |
28 | } | 26 | } |
29 | 27 | ||
30 | public function getSubscribedEvents() | 28 | public static function getSubscribedEvents() |
31 | { | 29 | { |
32 | return array( | 30 | return [ |
33 | 'prePersist', | 31 | EntrySavedEvent::NAME => 'onEntrySaved', |
34 | 'preUpdate', | 32 | EntryDeletedEvent::NAME => 'onEntryDeleted', |
35 | ); | 33 | ]; |
36 | } | 34 | } |
37 | 35 | ||
38 | /** | 36 | /** |
39 | * In case of an entry has been updated. | 37 | * Download images and updated the data into the entry. |
40 | * We won't update the content field if it wasn't updated. | ||
41 | * | 38 | * |
42 | * @param LifecycleEventArgs $args | 39 | * @param EntrySavedEvent $event |
43 | */ | 40 | */ |
44 | public function preUpdate(LifecycleEventArgs $args) | 41 | public function onEntrySaved(EntrySavedEvent $event) |
45 | { | 42 | { |
46 | $entity = $args->getEntity(); | 43 | if (!$this->enabled) { |
44 | $this->logger->debug('DownloadImagesSubscriber: disabled.'); | ||
47 | 45 | ||
48 | if (!$entity instanceof Entry) { | ||
49 | return; | 46 | return; |
50 | } | 47 | } |
51 | 48 | ||
52 | $config = new $this->configClass(); | 49 | $entry = $event->getEntry(); |
53 | $config->setEntityManager($args->getEntityManager()); | ||
54 | |||
55 | if (!$config->get('download_images_enabled')) { | ||
56 | return; | ||
57 | } | ||
58 | 50 | ||
59 | // field content has been updated | 51 | $html = $this->downloadImages($entry); |
60 | if ($args->hasChangedField('content')) { | 52 | if (false !== $html) { |
61 | $html = $this->downloadImages($config, $entity); | 53 | $this->logger->debug('DownloadImagesSubscriber: updated html.'); |
62 | 54 | ||
63 | if (false !== $html) { | 55 | $entry->setContent($html); |
64 | $args->setNewValue('content', $html); | ||
65 | } | ||
66 | } | 56 | } |
67 | 57 | ||
68 | // field preview picture has been updated | 58 | // update preview picture |
69 | if ($args->hasChangedField('previewPicture')) { | 59 | $previewPicture = $this->downloadPreviewImage($entry); |
70 | $previewPicture = $this->downloadPreviewImage($config, $entity); | 60 | if (false !== $previewPicture) { |
61 | $this->logger->debug('DownloadImagesSubscriber: update preview picture.'); | ||
71 | 62 | ||
72 | if (false !== $previewPicture) { | 63 | $entry->setPreviewPicture($previewPicture); |
73 | $entity->setPreviewPicture($previewPicture); | ||
74 | } | ||
75 | } | 64 | } |
65 | |||
66 | $this->em->persist($entry); | ||
67 | $this->em->flush(); | ||
76 | } | 68 | } |
77 | 69 | ||
78 | /** | 70 | /** |
79 | * When a new entry is saved. | 71 | * Remove images related to the entry. |
80 | * | 72 | * |
81 | * @param LifecycleEventArgs $args | 73 | * @param EntryDeletedEvent $event |
82 | */ | 74 | */ |
83 | public function prePersist(LifecycleEventArgs $args) | 75 | public function onEntryDeleted(EntryDeletedEvent $event) |
84 | { | 76 | { |
85 | $entity = $args->getEntity(); | 77 | if (!$this->enabled) { |
86 | 78 | $this->logger->debug('DownloadImagesSubscriber: disabled.'); | |
87 | if (!$entity instanceof Entry) { | ||
88 | return; | ||
89 | } | ||
90 | |||
91 | $config = new $this->configClass(); | ||
92 | $config->setEntityManager($args->getEntityManager()); | ||
93 | 79 | ||
94 | if (!$config->get('download_images_enabled')) { | ||
95 | return; | 80 | return; |
96 | } | 81 | } |
97 | 82 | ||
98 | // update all images inside the html | 83 | $this->downloadImages->removeImages($event->getEntry()->getId()); |
99 | $html = $this->downloadImages($config, $entity); | ||
100 | if (false !== $html) { | ||
101 | $entity->setContent($html); | ||
102 | } | ||
103 | |||
104 | // update preview picture | ||
105 | $previewPicture = $this->downloadPreviewImage($config, $entity); | ||
106 | if (false !== $previewPicture) { | ||
107 | $entity->setPreviewPicture($previewPicture); | ||
108 | } | ||
109 | } | 84 | } |
110 | 85 | ||
111 | /** | 86 | /** |
@@ -113,16 +88,14 @@ class DownloadImagesSubscriber implements EventSubscriber | |||
113 | * | 88 | * |
114 | * @todo If we want to add async download, it should be done in that method | 89 | * @todo If we want to add async download, it should be done in that method |
115 | * | 90 | * |
116 | * @param Config $config | 91 | * @param Entry $entry |
117 | * @param Entry $entry | ||
118 | * | 92 | * |
119 | * @return string|false False in case of async | 93 | * @return string|false False in case of async |
120 | */ | 94 | */ |
121 | public function downloadImages(Config $config, Entry $entry) | 95 | private function downloadImages(Entry $entry) |
122 | { | 96 | { |
123 | $this->downloadImages->setWallabagUrl($config->get('wallabag_url')); | ||
124 | |||
125 | return $this->downloadImages->processHtml( | 97 | return $this->downloadImages->processHtml( |
98 | $entry->getId(), | ||
126 | $entry->getContent(), | 99 | $entry->getContent(), |
127 | $entry->getUrl() | 100 | $entry->getUrl() |
128 | ); | 101 | ); |
@@ -133,16 +106,14 @@ class DownloadImagesSubscriber implements EventSubscriber | |||
133 | * | 106 | * |
134 | * @todo If we want to add async download, it should be done in that method | 107 | * @todo If we want to add async download, it should be done in that method |
135 | * | 108 | * |
136 | * @param Config $config | 109 | * @param Entry $entry |
137 | * @param Entry $entry | ||
138 | * | 110 | * |
139 | * @return string|false False in case of async | 111 | * @return string|false False in case of async |
140 | */ | 112 | */ |
141 | public function downloadPreviewImage(Config $config, Entry $entry) | 113 | private function downloadPreviewImage(Entry $entry) |
142 | { | 114 | { |
143 | $this->downloadImages->setWallabagUrl($config->get('wallabag_url')); | ||
144 | |||
145 | return $this->downloadImages->processSingleImage( | 115 | return $this->downloadImages->processSingleImage( |
116 | $entry->getId(), | ||
146 | $entry->getPreviewPicture(), | 117 | $entry->getPreviewPicture(), |
147 | $entry->getUrl() | 118 | $entry->getUrl() |
148 | ); | 119 | ); |
diff --git a/src/Wallabag/CoreBundle/Helper/DownloadImages.php b/src/Wallabag/CoreBundle/Helper/DownloadImages.php index e7982c56..c5298236 100644 --- a/src/Wallabag/CoreBundle/Helper/DownloadImages.php +++ b/src/Wallabag/CoreBundle/Helper/DownloadImages.php | |||
@@ -6,6 +6,7 @@ use Psr\Log\LoggerInterface; | |||
6 | use Symfony\Component\DomCrawler\Crawler; | 6 | use Symfony\Component\DomCrawler\Crawler; |
7 | use GuzzleHttp\Client; | 7 | use GuzzleHttp\Client; |
8 | use Symfony\Component\HttpFoundation\File\MimeType\MimeTypeExtensionGuesser; | 8 | use Symfony\Component\HttpFoundation\File\MimeType\MimeTypeExtensionGuesser; |
9 | use Symfony\Component\Finder\Finder; | ||
9 | 10 | ||
10 | class DownloadImages | 11 | class DownloadImages |
11 | { | 12 | { |
@@ -17,10 +18,11 @@ class DownloadImages | |||
17 | private $mimeGuesser; | 18 | private $mimeGuesser; |
18 | private $wallabagUrl; | 19 | private $wallabagUrl; |
19 | 20 | ||
20 | public function __construct(Client $client, $baseFolder, LoggerInterface $logger) | 21 | public function __construct(Client $client, $baseFolder, $wallabagUrl, LoggerInterface $logger) |
21 | { | 22 | { |
22 | $this->client = $client; | 23 | $this->client = $client; |
23 | $this->baseFolder = $baseFolder; | 24 | $this->baseFolder = $baseFolder; |
25 | $this->wallabagUrl = rtrim($wallabagUrl, '/'); | ||
24 | $this->logger = $logger; | 26 | $this->logger = $logger; |
25 | $this->mimeGuesser = new MimeTypeExtensionGuesser(); | 27 | $this->mimeGuesser = new MimeTypeExtensionGuesser(); |
26 | 28 | ||
@@ -28,17 +30,6 @@ class DownloadImages | |||
28 | } | 30 | } |
29 | 31 | ||
30 | /** | 32 | /** |
31 | * Since we can't inject CraueConfig service because it'll generate a circular reference when injected in the subscriber | ||
32 | * we use a different way to inject the current wallabag url. | ||
33 | * | ||
34 | * @param string $url Usually from `$config->get('wallabag_url')` | ||
35 | */ | ||
36 | public function setWallabagUrl($url) | ||
37 | { | ||
38 | $this->wallabagUrl = rtrim($url, '/'); | ||
39 | } | ||
40 | |||
41 | /** | ||
42 | * Setup base folder where all images are going to be saved. | 33 | * Setup base folder where all images are going to be saved. |
43 | */ | 34 | */ |
44 | private function setFolder() | 35 | private function setFolder() |
@@ -52,23 +43,24 @@ class DownloadImages | |||
52 | /** | 43 | /** |
53 | * Process the html and extract image from it, save them to local and return the updated html. | 44 | * Process the html and extract image from it, save them to local and return the updated html. |
54 | * | 45 | * |
46 | * @param int $entryId ID of the entry | ||
55 | * @param string $html | 47 | * @param string $html |
56 | * @param string $url Used as a base path for relative image and folder | 48 | * @param string $url Used as a base path for relative image and folder |
57 | * | 49 | * |
58 | * @return string | 50 | * @return string |
59 | */ | 51 | */ |
60 | public function processHtml($html, $url) | 52 | public function processHtml($entryId, $html, $url) |
61 | { | 53 | { |
62 | $crawler = new Crawler($html); | 54 | $crawler = new Crawler($html); |
63 | $result = $crawler | 55 | $result = $crawler |
64 | ->filterXpath('//img') | 56 | ->filterXpath('//img') |
65 | ->extract(array('src')); | 57 | ->extract(array('src')); |
66 | 58 | ||
67 | $relativePath = $this->getRelativePath($url); | 59 | $relativePath = $this->getRelativePath($entryId); |
68 | 60 | ||
69 | // download and save the image to the folder | 61 | // download and save the image to the folder |
70 | foreach ($result as $image) { | 62 | foreach ($result as $image) { |
71 | $imagePath = $this->processSingleImage($image, $url, $relativePath); | 63 | $imagePath = $this->processSingleImage($entryId, $image, $url, $relativePath); |
72 | 64 | ||
73 | if (false === $imagePath) { | 65 | if (false === $imagePath) { |
74 | continue; | 66 | continue; |
@@ -86,24 +78,27 @@ class DownloadImages | |||
86 | * - re-saved it (for security reason) | 78 | * - re-saved it (for security reason) |
87 | * - return the new local path. | 79 | * - return the new local path. |
88 | * | 80 | * |
81 | * @param int $entryId ID of the entry | ||
89 | * @param string $imagePath Path to the image to retrieve | 82 | * @param string $imagePath Path to the image to retrieve |
90 | * @param string $url Url from where the image were found | 83 | * @param string $url Url from where the image were found |
91 | * @param string $relativePath Relative local path to saved the image | 84 | * @param string $relativePath Relative local path to saved the image |
92 | * | 85 | * |
93 | * @return string Relative url to access the image from the web | 86 | * @return string Relative url to access the image from the web |
94 | */ | 87 | */ |
95 | public function processSingleImage($imagePath, $url, $relativePath = null) | 88 | public function processSingleImage($entryId, $imagePath, $url, $relativePath = null) |
96 | { | 89 | { |
97 | if (null == $relativePath) { | 90 | if (null === $relativePath) { |
98 | $relativePath = $this->getRelativePath($url); | 91 | $relativePath = $this->getRelativePath($entryId); |
99 | } | 92 | } |
100 | 93 | ||
94 | $this->logger->debug('DownloadImages: working on image: '.$imagePath); | ||
95 | |||
101 | $folderPath = $this->baseFolder.'/'.$relativePath; | 96 | $folderPath = $this->baseFolder.'/'.$relativePath; |
102 | 97 | ||
103 | // build image path | 98 | // build image path |
104 | $absolutePath = $this->getAbsoluteLink($url, $imagePath); | 99 | $absolutePath = $this->getAbsoluteLink($url, $imagePath); |
105 | if (false === $absolutePath) { | 100 | if (false === $absolutePath) { |
106 | $this->logger->log('error', 'Can not determine the absolute path for that image, skipping.'); | 101 | $this->logger->error('DownloadImages: Can not determine the absolute path for that image, skipping.'); |
107 | 102 | ||
108 | return false; | 103 | return false; |
109 | } | 104 | } |
@@ -111,15 +106,15 @@ class DownloadImages | |||
111 | try { | 106 | try { |
112 | $res = $this->client->get($absolutePath); | 107 | $res = $this->client->get($absolutePath); |
113 | } catch (\Exception $e) { | 108 | } catch (\Exception $e) { |
114 | $this->logger->log('error', 'Can not retrieve image, skipping.', ['exception' => $e]); | 109 | $this->logger->error('DownloadImages: Can not retrieve image, skipping.', ['exception' => $e]); |
115 | 110 | ||
116 | return false; | 111 | return false; |
117 | } | 112 | } |
118 | 113 | ||
119 | $ext = $this->mimeGuesser->guess($res->getHeader('content-type')); | 114 | $ext = $this->mimeGuesser->guess($res->getHeader('content-type')); |
120 | $this->logger->log('debug', 'Checking extension', ['ext' => $ext, 'header' => $res->getHeader('content-type')]); | 115 | $this->logger->debug('DownloadImages: Checking extension', ['ext' => $ext, 'header' => $res->getHeader('content-type')]); |
121 | if (!in_array($ext, ['jpeg', 'jpg', 'gif', 'png'], true)) { | 116 | if (!in_array($ext, ['jpeg', 'jpg', 'gif', 'png'], true)) { |
122 | $this->logger->log('error', 'Processed image with not allowed extension. Skipping '.$imagePath); | 117 | $this->logger->error('DownloadImages: Processed image with not allowed extension. Skipping '.$imagePath); |
123 | 118 | ||
124 | return false; | 119 | return false; |
125 | } | 120 | } |
@@ -133,7 +128,7 @@ class DownloadImages | |||
133 | } | 128 | } |
134 | 129 | ||
135 | if (false === $im) { | 130 | if (false === $im) { |
136 | $this->logger->log('error', 'Error while regenerating image', ['path' => $localPath]); | 131 | $this->logger->error('DownloadImages: Error while regenerating image', ['path' => $localPath]); |
137 | 132 | ||
138 | return false; | 133 | return false; |
139 | } | 134 | } |
@@ -141,16 +136,16 @@ class DownloadImages | |||
141 | switch ($ext) { | 136 | switch ($ext) { |
142 | case 'gif': | 137 | case 'gif': |
143 | $result = imagegif($im, $localPath); | 138 | $result = imagegif($im, $localPath); |
144 | $this->logger->log('debug', 'Re-creating gif'); | 139 | $this->logger->debug('DownloadImages: Re-creating gif'); |
145 | break; | 140 | break; |
146 | case 'jpeg': | 141 | case 'jpeg': |
147 | case 'jpg': | 142 | case 'jpg': |
148 | $result = imagejpeg($im, $localPath, self::REGENERATE_PICTURES_QUALITY); | 143 | $result = imagejpeg($im, $localPath, self::REGENERATE_PICTURES_QUALITY); |
149 | $this->logger->log('debug', 'Re-creating jpg'); | 144 | $this->logger->debug('DownloadImages: Re-creating jpg'); |
150 | break; | 145 | break; |
151 | case 'png': | 146 | case 'png': |
152 | $result = imagepng($im, $localPath, ceil(self::REGENERATE_PICTURES_QUALITY / 100 * 9)); | 147 | $result = imagepng($im, $localPath, ceil(self::REGENERATE_PICTURES_QUALITY / 100 * 9)); |
153 | $this->logger->log('debug', 'Re-creating png'); | 148 | $this->logger->debug('DownloadImages: Re-creating png'); |
154 | } | 149 | } |
155 | 150 | ||
156 | imagedestroy($im); | 151 | imagedestroy($im); |
@@ -159,23 +154,46 @@ class DownloadImages | |||
159 | } | 154 | } |
160 | 155 | ||
161 | /** | 156 | /** |
157 | * Remove all images for the given entry id. | ||
158 | * | ||
159 | * @param int $entryId ID of the entry | ||
160 | */ | ||
161 | public function removeImages($entryId) | ||
162 | { | ||
163 | $relativePath = $this->getRelativePath($entryId); | ||
164 | $folderPath = $this->baseFolder.'/'.$relativePath; | ||
165 | |||
166 | $finder = new Finder(); | ||
167 | $finder | ||
168 | ->files() | ||
169 | ->ignoreDotFiles(true) | ||
170 | ->in($folderPath); | ||
171 | |||
172 | foreach ($finder as $file) { | ||
173 | @unlink($file->getRealPath()); | ||
174 | } | ||
175 | |||
176 | @rmdir($folderPath); | ||
177 | } | ||
178 | |||
179 | /** | ||
162 | * Generate the folder where we are going to save images based on the entry url. | 180 | * Generate the folder where we are going to save images based on the entry url. |
163 | * | 181 | * |
164 | * @param string $url | 182 | * @param int $entryId ID of the entry |
165 | * | 183 | * |
166 | * @return string | 184 | * @return string |
167 | */ | 185 | */ |
168 | private function getRelativePath($url) | 186 | private function getRelativePath($entryId) |
169 | { | 187 | { |
170 | $hashUrl = hash('crc32', $url); | 188 | $hashId = hash('crc32', $entryId); |
171 | $relativePath = $hashUrl[0].'/'.$hashUrl[1].'/'.$hashUrl; | 189 | $relativePath = $hashId[0].'/'.$hashId[1].'/'.$hashId; |
172 | $folderPath = $this->baseFolder.'/'.$relativePath; | 190 | $folderPath = $this->baseFolder.'/'.$relativePath; |
173 | 191 | ||
174 | if (!file_exists($folderPath)) { | 192 | if (!file_exists($folderPath)) { |
175 | mkdir($folderPath, 0777, true); | 193 | mkdir($folderPath, 0777, true); |
176 | } | 194 | } |
177 | 195 | ||
178 | $this->logger->log('debug', 'Folder used for that url', ['folder' => $folderPath, 'url' => $url]); | 196 | $this->logger->debug('DownloadImages: Folder used for that Entry id', ['folder' => $folderPath, 'entryId' => $entryId]); |
179 | 197 | ||
180 | return $relativePath; | 198 | return $relativePath; |
181 | } | 199 | } |
@@ -208,7 +226,7 @@ class DownloadImages | |||
208 | return $absolute->get_uri(); | 226 | return $absolute->get_uri(); |
209 | } | 227 | } |
210 | 228 | ||
211 | $this->logger->log('error', 'Can not make an absolute link', ['base' => $base, 'url' => $url]); | 229 | $this->logger->error('DownloadImages: Can not make an absolute link', ['base' => $base, 'url' => $url]); |
212 | 230 | ||
213 | return false; | 231 | return false; |
214 | } | 232 | } |
diff --git a/src/Wallabag/CoreBundle/Resources/config/services.yml b/src/Wallabag/CoreBundle/Resources/config/services.yml index 1fb81a46..56d776ad 100644 --- a/src/Wallabag/CoreBundle/Resources/config/services.yml +++ b/src/Wallabag/CoreBundle/Resources/config/services.yml | |||
@@ -140,17 +140,19 @@ services: | |||
140 | wallabag_core.subscriber.download_images: | 140 | wallabag_core.subscriber.download_images: |
141 | class: Wallabag\CoreBundle\Event\Subscriber\DownloadImagesSubscriber | 141 | class: Wallabag\CoreBundle\Event\Subscriber\DownloadImagesSubscriber |
142 | arguments: | 142 | arguments: |
143 | - "@doctrine.orm.default_entity_manager" | ||
143 | - "@wallabag_core.entry.download_images" | 144 | - "@wallabag_core.entry.download_images" |
144 | - "%craue_config.config.class%" | 145 | - '@=service(''craue_config'').get(''download_images_enabled'')' |
145 | - "@logger" | 146 | - "@logger" |
146 | tags: | 147 | tags: |
147 | - { name: doctrine.event_subscriber } | 148 | - { name: kernel.event_subscriber } |
148 | 149 | ||
149 | wallabag_core.entry.download_images: | 150 | wallabag_core.entry.download_images: |
150 | class: Wallabag\CoreBundle\Helper\DownloadImages | 151 | class: Wallabag\CoreBundle\Helper\DownloadImages |
151 | arguments: | 152 | arguments: |
152 | - "@wallabag_core.entry.download_images.client" | 153 | - "@wallabag_core.entry.download_images.client" |
153 | - "%kernel.root_dir%/../web/assets/images" | 154 | - "%kernel.root_dir%/../web/assets/images" |
155 | - '@=service(''craue_config'').get(''wallabag_url'')' | ||
154 | - "@logger" | 156 | - "@logger" |
155 | 157 | ||
156 | wallabag_core.entry.download_images.client: | 158 | wallabag_core.entry.download_images.client: |
diff --git a/tests/Wallabag/CoreBundle/Controller/EntryControllerTest.php b/tests/Wallabag/CoreBundle/Controller/EntryControllerTest.php index 514e9d89..4ab06dbf 100644 --- a/tests/Wallabag/CoreBundle/Controller/EntryControllerTest.php +++ b/tests/Wallabag/CoreBundle/Controller/EntryControllerTest.php | |||
@@ -869,10 +869,30 @@ class EntryControllerTest extends WallabagCoreTestCase | |||
869 | $this->assertInstanceOf('Wallabag\CoreBundle\Entity\Entry', $entry); | 869 | $this->assertInstanceOf('Wallabag\CoreBundle\Entity\Entry', $entry); |
870 | $this->assertEquals($url, $entry->getUrl()); | 870 | $this->assertEquals($url, $entry->getUrl()); |
871 | $this->assertContains('Perpignan', $entry->getTitle()); | 871 | $this->assertContains('Perpignan', $entry->getTitle()); |
872 | $this->assertContains('assets/images/8/e/8ec9229a/d9bc0fcd.jpeg', $entry->getContent()); | 872 | $this->assertContains('/d9bc0fcd.jpeg', $entry->getContent()); |
873 | 873 | ||
874 | $em->remove($entry); | 874 | $client->getContainer()->get('craue_config')->set('download_images_enabled', 0); |
875 | $em->flush(); | 875 | } |
876 | |||
877 | /** | ||
878 | * @depends testNewEntryWithDownloadImagesEnabled | ||
879 | */ | ||
880 | public function testRemoveEntryWithDownloadImagesEnabled() | ||
881 | { | ||
882 | $this->logInAs('admin'); | ||
883 | $client = $this->getClient(); | ||
884 | |||
885 | $url = 'http://www.20minutes.fr/montpellier/1952003-20161030-video-car-tombe-panne-rugbymen-perpignan-improvisent-melee-route'; | ||
886 | $client->getContainer()->get('craue_config')->set('download_images_enabled', 1); | ||
887 | |||
888 | $content = $client->getContainer() | ||
889 | ->get('doctrine.orm.entity_manager') | ||
890 | ->getRepository('WallabagCoreBundle:Entry') | ||
891 | ->findByUrlAndUserId($url, $this->getLoggedInUserId()); | ||
892 | |||
893 | $client->request('GET', '/delete/'.$content->getId()); | ||
894 | |||
895 | $this->assertEquals(302, $client->getResponse()->getStatusCode()); | ||
876 | 896 | ||
877 | $client->getContainer()->get('craue_config')->set('download_images_enabled', 0); | 897 | $client->getContainer()->get('craue_config')->set('download_images_enabled', 0); |
878 | } | 898 | } |
diff --git a/tests/Wallabag/CoreBundle/Helper/DownloadImagesTest.php b/tests/Wallabag/CoreBundle/Helper/DownloadImagesTest.php index 33d2e389..920c21d9 100644 --- a/tests/Wallabag/CoreBundle/Helper/DownloadImagesTest.php +++ b/tests/Wallabag/CoreBundle/Helper/DownloadImagesTest.php | |||
@@ -26,12 +26,11 @@ class DownloadImagesTest extends \PHPUnit_Framework_TestCase | |||
26 | $logHandler = new TestHandler(); | 26 | $logHandler = new TestHandler(); |
27 | $logger = new Logger('test', array($logHandler)); | 27 | $logger = new Logger('test', array($logHandler)); |
28 | 28 | ||
29 | $download = new DownloadImages($client, sys_get_temp_dir().'/wallabag_test', $logger); | 29 | $download = new DownloadImages($client, sys_get_temp_dir().'/wallabag_test', 'http://wallabag.io/', $logger); |
30 | $download->setWallabagUrl('http://wallabag.io/'); | ||
31 | 30 | ||
32 | $res = $download->processHtml('<div><img src="http://i.imgur.com/T9qgcHc.jpg" /></div>', 'http://imgur.com/gallery/WxtWY'); | 31 | $res = $download->processHtml(123, '<div><img src="http://i.imgur.com/T9qgcHc.jpg" /></div>', 'http://imgur.com/gallery/WxtWY'); |
33 | 32 | ||
34 | $this->assertContains('http://wallabag.io/assets/images/4/2/4258f71e/c638b4c2.png', $res); | 33 | $this->assertContains('http://wallabag.io/assets/images/9/b/9b0ead26/c638b4c2.png', $res); |
35 | } | 34 | } |
36 | 35 | ||
37 | public function testProcessHtmlWithBadImage() | 36 | public function testProcessHtmlWithBadImage() |
@@ -47,8 +46,8 @@ class DownloadImagesTest extends \PHPUnit_Framework_TestCase | |||
47 | $logHandler = new TestHandler(); | 46 | $logHandler = new TestHandler(); |
48 | $logger = new Logger('test', array($logHandler)); | 47 | $logger = new Logger('test', array($logHandler)); |
49 | 48 | ||
50 | $download = new DownloadImages($client, sys_get_temp_dir().'/wallabag_test', $logger); | 49 | $download = new DownloadImages($client, sys_get_temp_dir().'/wallabag_test', 'http://wallabag.io/', $logger); |
51 | $res = $download->processHtml('<div><img src="http://i.imgur.com/T9qgcHc.jpg" /></div>', 'http://imgur.com/gallery/WxtWY'); | 50 | $res = $download->processHtml(123, '<div><img src="http://i.imgur.com/T9qgcHc.jpg" /></div>', 'http://imgur.com/gallery/WxtWY'); |
52 | 51 | ||
53 | $this->assertContains('http://i.imgur.com/T9qgcHc.jpg', $res, 'Image were not replace because of content-type'); | 52 | $this->assertContains('http://i.imgur.com/T9qgcHc.jpg', $res, 'Image were not replace because of content-type'); |
54 | } | 53 | } |
@@ -79,10 +78,10 @@ class DownloadImagesTest extends \PHPUnit_Framework_TestCase | |||
79 | $logHandler = new TestHandler(); | 78 | $logHandler = new TestHandler(); |
80 | $logger = new Logger('test', array($logHandler)); | 79 | $logger = new Logger('test', array($logHandler)); |
81 | 80 | ||
82 | $download = new DownloadImages($client, sys_get_temp_dir().'/wallabag_test', $logger); | 81 | $download = new DownloadImages($client, sys_get_temp_dir().'/wallabag_test', 'http://wallabag.io/', $logger); |
83 | $res = $download->processSingleImage('T9qgcHc.jpg', 'http://imgur.com/gallery/WxtWY'); | 82 | $res = $download->processSingleImage(123, 'T9qgcHc.jpg', 'http://imgur.com/gallery/WxtWY'); |
84 | 83 | ||
85 | $this->assertContains('/assets/images/4/2/4258f71e/ebe60399.'.$extension, $res); | 84 | $this->assertContains('/assets/images/9/b/9b0ead26/ebe60399.'.$extension, $res); |
86 | } | 85 | } |
87 | 86 | ||
88 | public function testProcessSingleImageWithBadUrl() | 87 | public function testProcessSingleImageWithBadUrl() |
@@ -98,8 +97,8 @@ class DownloadImagesTest extends \PHPUnit_Framework_TestCase | |||
98 | $logHandler = new TestHandler(); | 97 | $logHandler = new TestHandler(); |
99 | $logger = new Logger('test', array($logHandler)); | 98 | $logger = new Logger('test', array($logHandler)); |
100 | 99 | ||
101 | $download = new DownloadImages($client, sys_get_temp_dir().'/wallabag_test', $logger); | 100 | $download = new DownloadImages($client, sys_get_temp_dir().'/wallabag_test', 'http://wallabag.io/', $logger); |
102 | $res = $download->processSingleImage('T9qgcHc.jpg', 'http://imgur.com/gallery/WxtWY'); | 101 | $res = $download->processSingleImage(123, 'T9qgcHc.jpg', 'http://imgur.com/gallery/WxtWY'); |
103 | 102 | ||
104 | $this->assertFalse($res, 'Image can not be found, so it will not be replaced'); | 103 | $this->assertFalse($res, 'Image can not be found, so it will not be replaced'); |
105 | } | 104 | } |
@@ -117,8 +116,8 @@ class DownloadImagesTest extends \PHPUnit_Framework_TestCase | |||
117 | $logHandler = new TestHandler(); | 116 | $logHandler = new TestHandler(); |
118 | $logger = new Logger('test', array($logHandler)); | 117 | $logger = new Logger('test', array($logHandler)); |
119 | 118 | ||
120 | $download = new DownloadImages($client, sys_get_temp_dir().'/wallabag_test', $logger); | 119 | $download = new DownloadImages($client, sys_get_temp_dir().'/wallabag_test', 'http://wallabag.io/', $logger); |
121 | $res = $download->processSingleImage('http://i.imgur.com/T9qgcHc.jpg', 'http://imgur.com/gallery/WxtWY'); | 120 | $res = $download->processSingleImage(123, 'http://i.imgur.com/T9qgcHc.jpg', 'http://imgur.com/gallery/WxtWY'); |
122 | 121 | ||
123 | $this->assertFalse($res, 'Image can not be loaded, so it will not be replaced'); | 122 | $this->assertFalse($res, 'Image can not be loaded, so it will not be replaced'); |
124 | } | 123 | } |
@@ -136,8 +135,8 @@ class DownloadImagesTest extends \PHPUnit_Framework_TestCase | |||
136 | $logHandler = new TestHandler(); | 135 | $logHandler = new TestHandler(); |
137 | $logger = new Logger('test', array($logHandler)); | 136 | $logger = new Logger('test', array($logHandler)); |
138 | 137 | ||
139 | $download = new DownloadImages($client, sys_get_temp_dir().'/wallabag_test', $logger); | 138 | $download = new DownloadImages($client, sys_get_temp_dir().'/wallabag_test', 'http://wallabag.io/', $logger); |
140 | $res = $download->processSingleImage('/i.imgur.com/T9qgcHc.jpg', 'imgur.com/gallery/WxtWY'); | 139 | $res = $download->processSingleImage(123, '/i.imgur.com/T9qgcHc.jpg', 'imgur.com/gallery/WxtWY'); |
141 | 140 | ||
142 | $this->assertFalse($res, 'Absolute image can not be determined, so it will not be replaced'); | 141 | $this->assertFalse($res, 'Absolute image can not be determined, so it will not be replaced'); |
143 | } | 142 | } |