Skip to content

Commit

Permalink
feat: add test button and active field
Browse files Browse the repository at this point in the history
  • Loading branch information
tinect authored Jul 2, 2023
1 parent 767927a commit ed38f07
Show file tree
Hide file tree
Showing 21 changed files with 445 additions and 9 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG_en-GB.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
# 3.0.4
* Add configuration within the plugin to activate its function explicit
* Add button to test the service with a sample image

# 3.0.3
* Adjust wordings and remove typos

Expand Down
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,13 +53,17 @@ You may want to delete folder `thumbnails` within folder `public`

## Adding more thumbnail sizes:
- Save new size in the folder of the media management
- (up to and including plugin version 3.0.1) then run the command `bin/console media:generate-thumbnails` on the console to update the thumbnails for all images in the database
- (no more needed from version 3.0.2) run the command `bin/console media:generate-thumbnails` on the console to update the thumbnails for all images in the database
- Clear shop cache

## Find Patterns

You can find patterns in [GitHub Discussions in category Patterns](https://github.com/FriendsOfShopware/FroshPlatformThumbnailProcessor/discussions/categories/patterns)

## Uninstall

After uninstalling plugin you have to run `bin/console media:generate-thumbnails -strict` to generate the thumbnails-files on disk.

## License

The MIT License (MIT). Please see [License File](LICENSE) for more information.
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
"thumbnail"
],
"description": "This plugins allows you to use variable thumbnails, without having them on storage.",
"version": "3.0.3",
"version": "3.0.4",
"type": "shopware-platform-plugin",
"license": "mit",
"authors": [
Expand Down
1 change: 1 addition & 0 deletions phpstan.neon
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ parameters:
message: "#^Call to an undefined method Shopware\\\\Core\\\\Content\\\\Media\\\\Message\\\\GenerateThumbnailsMessage\\:\\:setContext\\(\\)\\.$#"
count: 1
path: src/DependencyInjection/FileSaver.php
reportUnmatched: false

-
message: "#^Parameter \\#1 \\$objectOrClass of class ReflectionClass constructor expects class\\-string\\<T of object\\>\\|T of object, string given\\.$#"
Expand Down
141 changes: 141 additions & 0 deletions src/Controller/Api/TestController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
<?php declare(strict_types=1);

namespace Frosh\ThumbnailProcessor\Controller\Api;

use Shopware\Core\Content\Media\Aggregate\MediaThumbnail\MediaThumbnailEntity;
use Shopware\Core\Content\Media\File\FileFetcher;
use Shopware\Core\Content\Media\File\FileSaver;
use Shopware\Core\Content\Media\MediaEntity;
use Shopware\Core\Content\Media\Pathname\UrlGeneratorInterface;
use Shopware\Core\Framework\Context;
use Shopware\Core\Framework\DataAbstractionLayer\EntityRepository;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter;
use Shopware\Core\Framework\Validation\DataBag\RequestDataBag;
use Shopware\Core\PlatformRequest;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;

#[Route(defaults: ['_routeScope' => ['api']])]
class TestController
{
public const REQUEST_ATTRIBUTE_TEST_ACTIVE = 'FroshPlatformThumbnailProcessorTestActive';

public function __construct(
private readonly UrlGeneratorInterface $urlGenerator,
private readonly EntityRepository $mediaRepository,
private readonly EntityRepository $mediaFolderRepository,
private readonly FileSaver $fileSaver,
private readonly FileFetcher $fileFetcher
) {
}

#[Route(path: '/api/_action/thumbnail-processor-test/get-sample-image')]
public function check(Request $request, RequestDataBag $dataBag): JsonResponse
{
if (!$dataBag->has('salesChannelId')) {
return new JsonResponse(['success' => false]);
}

$testFile = \realpath(__DIR__ . '/../../Resources/data/froshthumbnailprocessortestimage.jpg');

if (!\is_string($testFile) || !\is_file($testFile)) {
throw new \RuntimeException(\sprintf('Test file at "%s" is missing', $testFile));
}

$fileContent = \file_get_contents($testFile);

if (!\is_string($fileContent)) {
throw new \RuntimeException(\sprintf('Test file at "%s" could not be read', $testFile));
}

$request->attributes->set(self::REQUEST_ATTRIBUTE_TEST_ACTIVE, '1');

$salesChannelId = $dataBag->get('salesChannelId');
if (\is_string($salesChannelId)) {
$request->attributes->set(PlatformRequest::ATTRIBUTE_SALES_CHANNEL_ID, $salesChannelId);
}

$media = $this->getSampleMedia($fileContent, $testFile);

$thumbnail = new MediaThumbnailEntity();
$thumbnail->setWidth(200);
$thumbnail->setHeight(200);

return new JsonResponse(['url' => $this->urlGenerator->getAbsoluteThumbnailUrl($media, $thumbnail)]);
}

private function getProductFolderId(Context $context): string
{
$criteria = (new Criteria())
->addFilter(new EqualsFilter('media_folder.defaultFolder.entity', 'product'))
->addAssociation('defaultFolder')
->setLimit(1);

$ids = $this->mediaFolderRepository
->searchIds($criteria, $context)
->getIds();

if (\is_string($ids[0])) {
return $ids[0];
}

throw new \RuntimeException('Media folder for product could not have been found!');
}

private function getSampleMedia(string $fileContent, string $testFile): MediaEntity
{
$context = Context::createDefaultContext();
$mediaId = \hash('xxh128', $fileContent);

$existingMedia = $this->getMediaById($mediaId, $context);
if ($existingMedia) {
return $existingMedia;
}

$mediaFolderId = $this->getProductFolderId($context);

$this->mediaRepository->upsert(
[
[
'id' => $mediaId,
'mediaFolderId' => $mediaFolderId,
],
],
$context
);

$pathInfo = pathinfo($testFile);
if (empty($pathInfo['extension'])) {
$pathInfo['extension'] = 'jpg';
}

$uploadedFile = $this->fileFetcher->fetchBlob(
$fileContent,
$pathInfo['extension'],
'image/' . $pathInfo['extension']
);

$this->fileSaver->persistFileToMedia(
$uploadedFile,
$pathInfo['filename'],
$mediaId,
$context
);

$existingMedia = $this->getMediaById($mediaId, $context);
if ($existingMedia) {
return $existingMedia;
}

throw new \RuntimeException('Media has not been saved!');
}

private function getMediaById(string $id, Context $context): ?MediaEntity
{
$criteria = new Criteria([$id]);

return $this->mediaRepository->search($criteria, $context)->getEntities()->first();
}
}
57 changes: 57 additions & 0 deletions src/Migration/Migration1686772873AddActiveConfig.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<?php declare(strict_types=1);

namespace Frosh\ThumbnailProcessor\Migration;

use Doctrine\DBAL\Connection;
use Shopware\Core\Framework\Migration\MigrationStep;

class Migration1686772873AddActiveConfig extends MigrationStep
{
public function getCreationTimestamp(): int
{
return 1686772873;
}

public function update(Connection $connection): void
{
$currentPluginVersion = $this->getPluginVersion($connection);

if (empty($currentPluginVersion)) {
return;
}

// we added the active flag with version 3.0.3, so we don't need to set the default value afterward
if (\version_compare($currentPluginVersion, '3.0.3', '>')) {
return;
}

$connection->update(
'system_config',
[
'configuration_value' => '{"_value": true}',
],
['configuration_key' => 'FroshPlatformThumbnailProcessor.config.Active']
);
}

public function updateDestructive(Connection $connection): void
{
}

private function getPluginVersion(Connection $connection): ?string
{
$builder = $connection->createQueryBuilder()->select('`version`')
->from('plugin')
->where('`name` = :pluginName')
->andWhere('`active` = 1')
->setParameter('pluginName', 'FroshPlatformThumbnailProcessor');

$result = $builder->executeQuery()->fetchOne();

if (\is_string($result)) {
return $result;
}

return null;
}
}
4 changes: 3 additions & 1 deletion src/Resources/app/administration/src/main.js
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
import './frosh-thumbnail-processor-info-texts';
import './module/frosh-thumbnail-processor/frosh-thumbnail-processor-info-texts';
import './module/frosh-thumbnail-processor/test-button'
import './service/thumbnailProcessorTestService';
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"thumbnail-processor": {
"test": {
"title": "Service Test",
"success": "Seems good! Please check the displayed sample image to contain lighten trees view.",
"error": {
"general": "There was an error loading the image. Please check the url and setting.",
"noResize": "The used service does not resize the image."
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
const {Component, Mixin} = Shopware;
import template from './test-button.html.twig';
import './style.css';

Component.register('thumbnailprocessor-test', {
template,

props: ['btnLabel'],
inject: ['thumbnailProcessorTest'],

mixins: [
Mixin.getByName('notification')
],

data() {
return {
isLoading: false,
isSuccessful: false,
};
},

computed: {
pluginSalesChannelId() {
let configData = this.$parent;
for (let i = 0; i < 20; i++) {
if (typeof configData.currentSalesChannelId != "undefined") {
return configData.currentSalesChannelId;
}

configData = configData.$parent;
}

throw "Can not get pluginConfigData";
}
},

methods: {
finish() {
this.isSuccessful = false;
},

showError(message, sampleUrl) {
this.isSuccessful = false;

if (sampleUrl) {
message += ' sample url: ' + sampleUrl;
}

this.createNotificationError({
title: this.$tc('thumbnail-processor.test.title'),
message: message
});
},

saveAndCheck() {
this.isLoading = true;
this.systemConfigSaveAll();
},

check() {
const me = this;

me.thumbnailProcessorTest.getUrl(this.pluginSalesChannelId).then((res) => {
if (res.url) {
me.isSuccessful = true;

const img = document.createElement('img');
img.width = 200;
img.height = 200;

img.onload = function() {
if (img.naturalWidth !== 200) {
me.showError(me.$tc('thumbnail-processor.test.error.noResize'), res.url);
}
};

img.onerror = function() {
me.showError(me.$tc('thumbnail-processor.test.error.general'), res.url);
};

img.src = res.url;

const testElement = document.querySelector('[name="FroshPlatformThumbnailProcessor.config.test"]');
const testImage = testElement.querySelector('.frosh-thumbnail-processor-testimage img');

if (testImage) {
testImage.replaceWith(img);
} else {
const testImageContainer = document.createElement('p');
testImageContainer.classList.add('frosh-thumbnail-processor-testimage');
testImageContainer.appendChild(img);
testElement.appendChild(testImageContainer);
}
} else {
me.showError(me.$tc('thumbnail-processor.test.error.general'));
}

setTimeout(() => {
this.isLoading = false;
}, 2500);
});
},

systemConfigSaveAll() {
const me = this;
let el = this.$parent;

for (let i = 0; i < 30; i++) {
if (typeof el.$refs.systemConfig != "undefined") {
return el.$refs.systemConfig.saveAll()
.then(() => {
me.check();
})
}

el = el.$parent;
}

throw "Can not get systemConfig";
}
}
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.frosh-thumbnail-processor-testimage {
margin: 20px 0;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<div>
<sw-button-process
:isLoading="isLoading"
:processSuccess="isSuccessful"
@process-finish="finish"
@click="saveAndCheck"
>{{ btnLabel }}</sw-button-process>
</div>
Loading

0 comments on commit ed38f07

Please sign in to comment.