Skip to content

Commit

Permalink
Merge pull request #38 from inpsyde/feature/http-downloader-translata…
Browse files Browse the repository at this point in the history
…ble-package

Make use of HttpDownloader and JsonFile for downloading the TranslatePackage translations.
  • Loading branch information
Chrico authored Apr 14, 2023
2 parents aad2a02 + cfd3398 commit 623b060
Show file tree
Hide file tree
Showing 7 changed files with 121 additions and 85 deletions.
10 changes: 8 additions & 2 deletions docs/Configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -249,8 +249,6 @@ By using the above configuration, the package `my/package-name` will have transl
The `directories` configuration, both by name and by type, supports
[dynamic resolving via placeholders](./Dynamic%20resolving%20api%20and%20directories.md).



## Virtual Packages

It might be desirable to install translations for packages that are *not* required in Composer.
Expand Down Expand Up @@ -291,3 +289,11 @@ passed, assuming latest version, if none is passed.

In any case, all three properties (if defined and not empty), will be used when building the
API endpoint (no matter if default or customized by name/type).

## Authentication for privately hosted translations

Your private GlotPress system is probably secured with one or more authentication options. In order to allow your project to have access to these endpoints and translations file archives you will have to tell Composer how to authenticate with the server that hosts them.

`inpsyde/wp-translation-downloader` makes use of the full Composer PHP API and therefor uses the `Composer\Util\HttpDownloader`. This implementation accesses internally the configured Composer defined credentials.

Credentials can be stored on 4 different places; in an `auth.json` for the project, a global `auth.json`, in the `composer.json` itself or in the `COMPOSER_AUTH` environment variable. Read more about configuration of authentication in Composer here: https://getcomposer.org/doc/articles/authentication-for-private-packages.md
54 changes: 4 additions & 50 deletions src/Package/TranslatablePackage.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,6 @@ class TranslatablePackage extends Package implements TranslatablePackageInterfac
*/
protected $endpoint;

/**
* @var bool
*/
private $translationLoaded = false;

/**
* @var string|null
*/
Expand All @@ -57,12 +52,14 @@ class TranslatablePackage extends Package implements TranslatablePackageInterfac
* @param string $directory
* @param string $endpoint
* @param string|null $endpointFileType
* @param array $translations
*/
public function __construct(
PackageInterface $package,
string $directory,
string $endpoint,
?string $endpointFileType = null
?string $endpointFileType,
array $translations
) {

parent::__construct(
Expand All @@ -78,15 +75,14 @@ public function __construct(
$this->endpoint = $endpoint;
$this->languageDirectory = $directory;
$this->endpointFileType = $endpointFileType;
$this->translations = $this->parseTranslations($translations);
}

/**
* {@inheritDoc}
*/
public function translations(array $allowedLanguages = []): array
{
$this->loadTranslations();

if (count($allowedLanguages) === 0) {
return $this->translations;
}
Expand All @@ -101,32 +97,6 @@ public function translations(array $allowedLanguages = []): array
return $filtered;
}

/**
* @return bool
*/
protected function loadTranslations(): bool
{
if ($this->translationLoaded) {
return false;
}
$this->translationLoaded = true;

$apiUrl = $this->apiEndpoint();
if ($apiUrl === '') {
return false;
}

$result = $this->readEndpointContent($apiUrl);
$translations = is_array($result) ? ($result['translations'] ?? null) : null;
if (!is_array($translations) || (count($translations) < 1)) {
return false;
}

$this->translations = $this->parseTranslations($translations);

return true;
}

/**
* {@inheritDoc}
*/
Expand Down Expand Up @@ -156,22 +126,6 @@ public function languageDirectory(): string
return $this->languageDirectory;
}

/**
* @param string $apiUrl
* @return array|null
*/
protected function readEndpointContent(string $apiUrl): ?array
{
$result = @file_get_contents($apiUrl);
if (!$result) {
return null;
}

$result = json_decode($result, true);

return is_array($result) ? $result : null;
}

/**
* @param array $translationsData
* @return list<ProjectTranslation>
Expand Down
66 changes: 53 additions & 13 deletions src/Package/TranslatablePackageFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,10 @@
use Composer\DependencyResolver\Operation\OperationInterface;
use Composer\DependencyResolver\Operation\UninstallOperation;
use Composer\DependencyResolver\Operation\UpdateOperation;
use Composer\IO\IOInterface;
use Composer\Json\JsonFile;
use Composer\Package\PackageInterface;
use Composer\Package\Version\VersionParser;
use Composer\Util\HttpDownloader;
use Inpsyde\WpTranslationDownloader\Config\PluginConfiguration;
use Inpsyde\WpTranslationDownloader\Util\FnMatcher;

Expand All @@ -31,16 +33,33 @@ class TranslatablePackageFactory
*/
protected $pluginConfiguration;

/**
* @var HttpDownloader
*/
protected $downloader;

/**
* @var IOInterface
*/
protected $io;

/**
* @param PluginConfiguration $pluginConfiguration
*/
public function __construct(PluginConfiguration $pluginConfiguration)
{
public function __construct(
PluginConfiguration $pluginConfiguration,
HttpDownloader $downloader,
IOInterface $io
) {

$this->pluginConfiguration = $pluginConfiguration;
$this->downloader = $downloader;
$this->io = $io;
}

/**
* @param UninstallOperation|UpdateOperation|InstallOperation|OperationInterface $operation
*
* @return null|TranslatablePackageInterface
* @throws \InvalidArgumentException
*/
Expand All @@ -65,19 +84,40 @@ public function createFromOperation(
*/
public function create(PackageInterface $package): ?TranslatablePackageInterface
{
$directory = $this->resolveDirectory($package);
if (!$directory) {
return null;
}
try {
$directory = $this->resolveDirectory($package);
if (! $directory) {
return null;
}

$endpointData = $this->resolveEndpoint($package);
if ($endpointData === null) {
return null;
}
$endpointData = $this->resolveEndpoint($package);
if ($endpointData === null) {
return null;
}

[$endpoint, $endpointType] = $endpointData;
[$endpoint, $endpointType] = $endpointData;

return new TranslatablePackage($package, $directory, $endpoint, $endpointType);
$jsonFile = new JsonFile($endpoint, $this->downloader, $this->io);
/** @var array|null $translations */
$translations = $jsonFile->read();
if (! $translations) {
return null;
}

$translations = (array) ($translations['translations'] ?? []);

return new TranslatablePackage(
$package,
$directory,
$endpoint,
$endpointType,
$translations
);
} catch (\Throwable $exception) {
$this->io->error($exception->getMessage());

return null;
}
}

/**
Expand Down
8 changes: 6 additions & 2 deletions src/Plugin.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
use Composer\Command\BaseCommand;
use Composer\Composer;
use Composer\EventDispatcher\EventSubscriberInterface;
use Composer\Factory;
use Composer\Installer\PackageEvent;
use Composer\IO\IOInterface;
use Composer\Package\CompletePackage;
Expand All @@ -30,7 +31,6 @@
use Inpsyde\WpTranslationDownloader\Command\DownloadCommand;
use Inpsyde\WpTranslationDownloader\Config\PluginConfiguration;
use Inpsyde\WpTranslationDownloader\Config\PluginConfigurationBuilder;
use Inpsyde\WpTranslationDownloader\Util\ArchiveDownloaderFactory;
use Inpsyde\WpTranslationDownloader\Util\Downloader;
use Inpsyde\WpTranslationDownloader\Package\TranslatablePackageFactory;
use Inpsyde\WpTranslationDownloader\Util\Locker;
Expand Down Expand Up @@ -147,7 +147,11 @@ public function activate(Composer $composer, IOInterface $io)
return;
}

$this->translatablePackageFactory = new TranslatablePackageFactory($this->pluginConfig);
$this->translatablePackageFactory = new TranslatablePackageFactory(
$this->pluginConfig,
Factory::createHttpDownloader($io, $composer->getConfig()),
$this->io
);

$this->translationsDownloader = new TranslationPackageDownloader(
$composer->getLoop(),
Expand Down
22 changes: 10 additions & 12 deletions tests/Unit/Package/ProjectTranslationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@

use Composer\Package\CompletePackage;
use Composer\Package\Package;
use Inpsyde\WpTranslationDownloader\Package\ProjectTranslation;
use Inpsyde\WpTranslationDownloader\Package\TranslatablePackage;
use PHPUnit\Framework\TestCase;

Expand All @@ -30,16 +29,10 @@ public function __construct(?string $endpointFileType, array $data)
new CompletePackage('test/test', '1.0.0.0', '1.0'),
__DIR__,
'https://example.com/test/test/translations',
$endpointFileType
$endpointFileType,
[$this->data]
);
}

protected function loadTranslations(): bool
{
$this->translations = $this->parseTranslations([$this->data]);

return true;
}
};

$translation = $translatable->translations()[0];
Expand Down Expand Up @@ -215,6 +208,7 @@ public function testGenerationFromParsedJson(): void
]
}
JSON;

$translatablePackage = new class ($json) extends TranslatablePackage
{
private $json;
Expand All @@ -224,15 +218,19 @@ public function __construct(string $json)
parent::__construct(
new Package('test/test', '2.0.5.0', '1.2.0.5'),
__DIR__,
'https://example.com'
'https://example.com',
null,
$this->readEndpointContent('')['translations'] ?? []
);
}

protected function readEndpointContent(string $apiUrl): ?array
protected function readEndpointContent(string $apiUrl): array
{
$result = json_decode($this->json, true);

return is_array($result) ? $result : null;
return is_array($result)
? $result
: [];
}
};

Expand Down
37 changes: 33 additions & 4 deletions tests/Unit/Package/TranslatablePackageFactoryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,11 @@
namespace Inpsyde\WpTranslationDownloader\Tests\Unit\Package;

use Composer\DependencyResolver\Operation\InstallOperation;
use Composer\IO\IOInterface;
use Composer\Package\Loader\ArrayLoader;
use Composer\Package\Package;
use Composer\Util\Http\Response;
use Composer\Util\HttpDownloader;
use Inpsyde\WpTranslationDownloader\Config\PluginConfiguration;
use Inpsyde\WpTranslationDownloader\Package\TranslatablePackageFactory;
use Inpsyde\WpTranslationDownloader\Package\TranslatablePackageInterface;
Expand All @@ -20,7 +23,21 @@ class TranslatablePackageFactoryTest extends TestCase
public function testCreateFromOperation(): void
{
$pluginConfiguration = new PluginConfiguration([]);
$packageFactory = new TranslatablePackageFactory($pluginConfiguration);

$responseStub = \Mockery::mock(Response::class);
$responseStub->expects('getBody')->andReturn('{"translations":{}}');

$downloaderStub = \Mockery::mock(HttpDownloader::class);
$downloaderStub->expects('get')->andReturn($responseStub);

$ioStub = \Mockery::mock(IOInterface::class);
$ioStub->allows('error');

$packageFactory = new TranslatablePackageFactory(
$pluginConfiguration,
$downloaderStub,
$ioStub
);

$expectedName = 'inpsyde/google-tag-manager';
$expectedType = 'wordpress-plugin';
Expand Down Expand Up @@ -49,7 +66,11 @@ public function testResolveEndpoint(
$loader = new ArrayLoader();
$pluginConfiguration = new PluginConfiguration($expectedApi);

$packageFactory = new TranslatablePackageFactory($pluginConfiguration);
$packageFactory = new TranslatablePackageFactory(
$pluginConfiguration,
\Mockery::mock(HttpDownloader::class),
\Mockery::mock(IOInterface::class)
);
$package = $loader->load($packageData);

static::assertSame($expected, $packageFactory->resolveEndpoint($package));
Expand Down Expand Up @@ -217,7 +238,11 @@ public function testReplacingPlaceholders(): void

$pluginConfiguration = new PluginConfiguration($api);

$packageFactory = new TranslatablePackageFactory($pluginConfiguration);
$packageFactory = new TranslatablePackageFactory(
$pluginConfiguration,
\Mockery::mock(HttpDownloader::class),
\Mockery::mock(IOInterface::class)
);

static::assertSame([$expectedUrl, null], $packageFactory->resolveEndpoint($package));
}
Expand All @@ -230,7 +255,11 @@ public function testResolveDirectory(array $input, array $packages): void
{
$pluginConfiguration = new PluginConfiguration($input);

$packageFactory = new TranslatablePackageFactory($pluginConfiguration);
$packageFactory = new TranslatablePackageFactory(
$pluginConfiguration,
\Mockery::mock(HttpDownloader::class),
\Mockery::mock(IOInterface::class)
);
foreach ($packages as $packageData) {
$version = $packageData['version'] ?? '1.0';
$package = new Package($packageData['name'], $version, $version);
Expand Down
Loading

0 comments on commit 623b060

Please sign in to comment.