Skip to content

Commit f5d689a

Browse files
committed
feat: integrate with shopware plugin system
1 parent 690de35 commit f5d689a

File tree

14 files changed

+394
-8
lines changed

14 files changed

+394
-8
lines changed

src/Action/LoadPluginAction.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,6 @@ public function execute(string|PackageIndexEntry $packageInformation): void
137137
$id = $plugin?->getId() ?? Uuid::randomHex();
138138

139139
$pluginData['id'] = $id;
140-
$pluginData['isInstalled'] = $plugin && $plugin->isInstalled();
141140

142141
$this->availableOpensourcePluginRepository->upsert([$pluginData], Context::createDefaultContext());
143142
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace NuonicPluginInstaller\Controller;
6+
7+
use NuonicPluginInstaller\Service\PackageService;
8+
use NuonicPluginInstaller\Struct\PackageVersion;
9+
use OpenApi\Attributes as OA;
10+
use Shopware\Core\Framework\Context;
11+
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
12+
use Symfony\Component\HttpFoundation\JsonResponse;
13+
use Symfony\Component\HttpFoundation\Request;
14+
use Symfony\Component\HttpFoundation\Response;
15+
use Symfony\Component\Routing\Attribute\Route;
16+
17+
#[Route(defaults: ['_routeScope' => ['api']])]
18+
class InstallController extends AbstractController
19+
{
20+
public function __construct(
21+
private readonly PackageService $packageService,
22+
) {
23+
}
24+
25+
#[OA\Post(
26+
path: '/api/_action/nuonic-plugin-installer/install',
27+
operationId: 'executeWebhook',
28+
requestBody: new OA\RequestBody(content: new OA\JsonContent()),
29+
tags: ['Admin Api'],
30+
responses: [
31+
new OA\Response(response: Response::HTTP_NO_CONTENT, description: 'MediaProxy returns data'),
32+
new OA\Response(response: Response::HTTP_BAD_REQUEST, description: 'Invalid input data'),
33+
]
34+
)]
35+
#[Route(
36+
path: '/api/_action/nuonic-plugin-installer/install',
37+
name: 'api.action.nuonic_plugin_installer.install.execute',
38+
defaults: ['auth_required' => false],
39+
methods: ['POST']
40+
)]
41+
public function execute(Request $request, Context $context): Response
42+
{
43+
$requestData = $request->toArray();
44+
if (!isset($requestData['package'], $requestData['version'])) {
45+
$this->malformedRequestError();
46+
}
47+
48+
$this->packageService->install(new PackageVersion(
49+
$requestData['package'],
50+
$requestData['version']
51+
), $context);
52+
53+
return new Response(status: 201);
54+
}
55+
56+
protected function malformedRequestError(): Response
57+
{
58+
return new JsonResponse(
59+
['status' => 'error', 'message' => 'Request data is not formed correctly.'],
60+
status: 400
61+
);
62+
}
63+
}
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace NuonicPluginInstaller\Controller;
6+
7+
use OpenApi\Attributes as OA;
8+
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
9+
use Symfony\Component\HttpFoundation\JsonResponse;
10+
use Symfony\Component\HttpFoundation\Request;
11+
use Symfony\Component\HttpFoundation\Response;
12+
use Symfony\Component\Routing\Attribute\Route;
13+
use Symfony\Contracts\HttpClient\HttpClientInterface;
14+
15+
#[Route(defaults: ['_routeScope' => ['api']])]
16+
class MediaProxyController extends AbstractController
17+
{
18+
public function __construct(
19+
private HttpClientInterface $client,
20+
) {
21+
}
22+
23+
#[OA\Post(
24+
path: '/api/_action/nuonic-plugin-installer/proxy',
25+
operationId: 'executeWebhook',
26+
tags: ['Admin Api'],
27+
parameters: [new OA\Parameter(
28+
parameter: 'url',
29+
name: 'url',
30+
in: 'query',
31+
schema: new OA\Schema(type: 'string')
32+
)],
33+
responses: [
34+
new OA\Response(response: Response::HTTP_NO_CONTENT, description: 'MediaProxy returns data'),
35+
new OA\Response(response: Response::HTTP_BAD_REQUEST, description: 'Invalid input data'),
36+
]
37+
)]
38+
#[Route(
39+
path: '/api/_action/nuonic-plugin-installer/proxy',
40+
name: 'api.action.nuonic_plugin_installer.proxy.execute',
41+
defaults: ['auth_required' => false],
42+
methods: ['GET']
43+
)]
44+
public function execute(Request $request): Response
45+
{
46+
/** @var string|null $url */
47+
$url = $request->query['url'];
48+
if (is_null($url) || !str_starts_with($url, 'https://raw.githubusercontent.com/')) {
49+
return $this->malformedRequestError();
50+
}
51+
52+
$response = $this->client->request('GET', $url);
53+
54+
if (Response::HTTP_OK !== $response->getStatusCode()) {
55+
return new Response(status: $response->getStatusCode());
56+
}
57+
58+
return new Response($response->getContent());
59+
}
60+
61+
protected function malformedRequestError(): Response
62+
{
63+
return new JsonResponse(
64+
['status' => 'error', 'message' => 'Request data is not formed correctly.'],
65+
status: 400
66+
);
67+
}
68+
}

src/Core/Framework/Plugin/AvailableOpensourcePlugin/Aggregate/AvailableOpensourcePluginTranslation/AvailableOpensourcePluginTranslationCollection.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66

77
use Shopware\Core\Framework\DataAbstractionLayer\EntityCollection;
88

9+
/**
10+
* @extends EntityCollection<AvailableOpensourcePluginTranslationEntity>
11+
*/
912
class AvailableOpensourcePluginTranslationCollection extends EntityCollection
1013
{
1114
protected function getExpectedClass(): string

src/Core/Framework/Plugin/AvailableOpensourcePlugin/AvailableOpensourcePluginCollection.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66

77
use Shopware\Core\Framework\DataAbstractionLayer\EntityCollection;
88

9+
/**
10+
* @extends EntityCollection<AvailableOpensourcePluginEntity>
11+
*/
912
class AvailableOpensourcePluginCollection extends EntityCollection
1013
{
1114
protected function getExpectedClass(): string

src/Core/Framework/Plugin/AvailableOpensourcePlugin/AvailableOpensourcePluginDefinition.php

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,18 @@
66

77
use NuonicPluginInstaller\Core\Framework\Plugin\AvailableOpensourcePlugin\Aggregate\AvailableOpensourcePluginTranslation\AvailableOpensourcePluginTranslationDefinition;
88
use Shopware\Core\Framework\DataAbstractionLayer\EntityDefinition;
9-
use Shopware\Core\Framework\DataAbstractionLayer\Field\BoolField;
9+
use Shopware\Core\Framework\DataAbstractionLayer\Field\FkField;
1010
use Shopware\Core\Framework\DataAbstractionLayer\Field\Flag\ApiAware;
1111
use Shopware\Core\Framework\DataAbstractionLayer\Field\Flag\PrimaryKey;
1212
use Shopware\Core\Framework\DataAbstractionLayer\Field\Flag\Required;
1313
use Shopware\Core\Framework\DataAbstractionLayer\Field\IdField;
1414
use Shopware\Core\Framework\DataAbstractionLayer\Field\JsonField;
15+
use Shopware\Core\Framework\DataAbstractionLayer\Field\OneToOneAssociationField;
1516
use Shopware\Core\Framework\DataAbstractionLayer\Field\StringField;
1617
use Shopware\Core\Framework\DataAbstractionLayer\Field\TranslatedField;
1718
use Shopware\Core\Framework\DataAbstractionLayer\Field\TranslationsAssociationField;
1819
use Shopware\Core\Framework\DataAbstractionLayer\FieldCollection;
20+
use Shopware\Core\Framework\Plugin\PluginDefinition;
1921

2022
class AvailableOpensourcePluginDefinition extends EntityDefinition
2123
{
@@ -50,11 +52,15 @@ protected function defineFields(): FieldCollection
5052
(new StringField('license', 'license'))->addFlags(new Required()),
5153
(new StringField('link', 'link'))->addFlags(new Required()),
5254
(new StringField('available_version', 'availableVersion'))->addFlags(new Required()),
53-
(new BoolField('is_installed', 'isInstalled'))->addFlags(new Required()),
55+
5456
(new TranslationsAssociationField(
5557
AvailableOpensourcePluginTranslationDefinition::class,
5658
'available_opensource_plugin_id'
5759
))->addFlags(new ApiAware(), new Required()),
60+
61+
new FkField('plugin_id', 'pluginId', PluginDefinition::class),
62+
new OneToOneAssociationField('plugin', 'plugin_id', 'id', PluginDefinition::class),
63+
5864
]);
5965
}
6066
}

src/Core/Framework/Plugin/AvailableOpensourcePlugin/AvailableOpensourcePluginEntity.php

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
use Shopware\Core\Framework\DataAbstractionLayer\Entity;
88
use Shopware\Core\Framework\DataAbstractionLayer\EntityIdTrait;
9+
use Shopware\Core\Framework\Plugin\PluginEntity;
910

1011
class AvailableOpensourcePluginEntity extends Entity
1112
{
@@ -31,7 +32,7 @@ class AvailableOpensourcePluginEntity extends Entity
3132

3233
protected string $availableVersion;
3334

34-
protected bool $isInstalled;
35+
protected PluginEntity $plugin;
3536

3637
public function getName(): string
3738
{
@@ -133,14 +134,14 @@ public function setAvailableVersion(string $availableVersion): void
133134
$this->availableVersion = $availableVersion;
134135
}
135136

136-
public function isInstalled(): bool
137+
public function getPlugin(): PluginEntity
137138
{
138-
return $this->isInstalled;
139+
return $this->plugin;
139140
}
140141

141-
public function setIsInstalled(bool $isInstalled): void
142+
public function setPlugin(PluginEntity $plugin): void
142143
{
143-
$this->isInstalled = $isInstalled;
144+
$this->plugin = $plugin;
144145
}
145146

146147
public function getApiAlias(): string
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
<?php declare(strict_types=1);
2+
3+
namespace NuonicPluginInstaller\Migration;
4+
5+
use Doctrine\DBAL\Connection;
6+
use Shopware\Core\Framework\Log\Package;
7+
use Shopware\Core\Framework\Migration\MigrationStep;
8+
9+
/**
10+
* @internal
11+
*/
12+
#[Package('core')]
13+
class Migration1741388682NuonicAvailableOpensourcePlugin extends MigrationStep
14+
{
15+
public function getCreationTimestamp(): int
16+
{
17+
return 1741388682;
18+
}
19+
20+
public function update(Connection $connection): void
21+
{
22+
$query = <<<'SQL'
23+
ALTER TABLE nuonic_available_opensource_plugin ADD plugin_id BINARY(16) DEFAULT NULL, DROP name, DROP description, DROP is_installed, CHANGE package_name package_name VARCHAR(255) NOT NULL;
24+
25+
ALTER TABLE nuonic_available_opensource_plugin ADD CONSTRAINT fk.nuonic_available_opensource_plugin.plugin_id FOREIGN KEY (plugin_id) REFERENCES plugin (id) ON UPDATE CASCADE ON DELETE SET NULL;
26+
SQL;
27+
28+
$connection->executeStatement($query);
29+
}
30+
31+
public function updateDestructive(Connection $connection): void
32+
{
33+
// Add destructive update if necessary
34+
}
35+
}

src/Resources/config/routes.xml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<?xml version="1.0" encoding="UTF-8" ?>
2+
<routes xmlns="http://symfony.com/schema/routing"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://symfony.com/schema/routing
5+
https://symfony.com/schema/routing/routing-1.0.xsd">
6+
<import resource="../../Controller/**/*Controller.php" type="attribute"/>
7+
</routes>

src/Resources/config/services.xml

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,5 +71,35 @@
7171
<argument type="service" id="NuonicPluginInstaller\Action\LoadPluginAction" />
7272
<tag name="console.command" />
7373
</service>
74+
75+
<service id="NuonicPluginInstaller\Service\PackageService">
76+
<argument type="service" id="Shopware\Core\Framework\Plugin\Composer\CommandExecutor" />
77+
<argument type="service" id="Shopware\Core\Framework\Plugin\PluginService" />
78+
</service>
79+
80+
<service id="NuonicPluginInstaller\Subscriber\RemovePackageSubscriber">
81+
<argument type="service" id="NuonicPluginInstaller\Service\PackageService" />
82+
<argument type="service" id="nuonic_available_opensource_plugin.repository" />
83+
<tag name="kernel.event_subscriber" />
84+
</service>
85+
86+
<service id="NuonicPluginInstaller\Subscriber\MarkInstalledPluginSubscriber">
87+
<argument type="service" id="nuonic_available_opensource_plugin.repository" />
88+
<tag name="kernel.event_subscriber" />
89+
</service>
90+
91+
<service id="NuonicPluginInstaller\Controller\MediaProxyController">
92+
<argument type="service" id="http_client" />
93+
<call method="setContainer">
94+
<argument type="service" id="service_container"/>
95+
</call>
96+
</service>
97+
98+
<service id="NuonicPluginInstaller\Controller\InstallController">
99+
<argument type="service" id="NuonicPluginInstaller\Service\PackageService" />
100+
<call method="setContainer">
101+
<argument type="service" id="service_container"/>
102+
</call>
103+
</service>
74104
</services>
75105
</container>

0 commit comments

Comments
 (0)