Skip to content

Commit

Permalink
feat!: read vendor folders and merge data
Browse files Browse the repository at this point in the history
  • Loading branch information
marcoraddatz committed May 16, 2024
1 parent 65a9adf commit 4d0ed30
Show file tree
Hide file tree
Showing 2 changed files with 143 additions and 34 deletions.
130 changes: 105 additions & 25 deletions src/Controllers/GetLocaleController.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,54 +10,134 @@

class GetLocaleController extends Controller
{
private const LOCALE_NOT_FOUND = 'Locale not found.';

/**
* Handle the incoming request.
*
* @throws \Throwable
*/
public function __invoke(string $locale): JsonResponse
{
// Doesn't match our whitelist
abort_unless(in_array($locale, config('locale-via-api.locales'), true), 404);

// Might be on whitelist, but doesn't exist
abort_unless(File::exists(lang_path($locale)), 404);
$this->ensureLocaleIsValid($locale);
$this->ensureLocaleExists($locale);

$data = Cache::driver(config('locale-via-api.cache.driver', 'sync'))->remember(
config('locale-via-api.cache.prefix', 'locale-via-api:') . $locale,
$data = Cache::driver(config('locale-via-api.cache.driver', 'array'))->remember(
$this->getCacheKey($locale),
config('locale-via-api.cache.duration', 3600),
function () use ($locale) {
return $this->getLocaleData($locale);
});
return $this->getMergedLocaleData($locale);
}
);

return response()->json([
'data' => $data,
'meta' => [
'hash' => md5(json_encode($data)),
],
]);
return $this->createJsonResponse($data);
}

/**
* Ensure the locale is valid.
*
* @throws \Symfony\Component\HttpKernel\Exception\HttpException
*/
private function ensureLocaleIsValid(string $locale): void
{
abort_unless(in_array($locale, config('locale-via-api.locales'), true), 404, self::LOCALE_NOT_FOUND);
}

/**
* Ensure the locale directory exists.
*
* @throws \Symfony\Component\HttpKernel\Exception\HttpException
*/
private function ensureLocaleExists(string $locale): void
{
abort_unless(File::exists(lang_path($locale)), 404, self::LOCALE_NOT_FOUND);
}

/**
* Get the cache key for the given locale.
*/
private function getCacheKey(string $locale): string
{
return config('locale-via-api.cache.prefix', 'locale-via-api:') . $locale;
}

/**
* Get merged locale data.
*/
private function getMergedLocaleData(string $locale): array
{
$data = $this->getLocaleData($locale);

// Get vendor directories
$vendorLocales = File::directories(lang_path('vendor'));

foreach ($vendorLocales as $vendorLocale) {
$vendorName = basename($vendorLocale);
$data = array_merge_recursive(
$data,
$this->getLocaleData(sprintf('vendor/%s/%s', $vendorName, $locale))
);
}

ksort($data);

return $data;
}

/**
* Get locale data from files.
*/
protected function getLocaleData(string $locale): array
{
$data = [];
$files = File::allFiles(lang_path($locale));
$directory = lang_path($locale);

foreach ($files as $file) {
$fileName = Str::before($file->getFilename(), '.');
if (! File::exists($directory)) {
return $data;
}

// No support for JSON files right now
$files = File::allFiles($directory);

foreach ($files as $file) {
if ($file->getExtension() !== 'php') {
continue;
}

// This is a directory
if (! Str::is($locale, $file->getRelativePath())) {
$fileName = Str::replace('/', '.', Str::before($file->getRelativePathname(), '.'));
$fileName = Str::replace($locale . '.', '', $fileName);
}

$fileName = $this->getLocaleFileName($file, $locale);
$data[$fileName] = File::getRequire($file);
}

return $data;
}

/**
* Get the locale file name.
*
* @param \Symfony\Component\Finder\SplFileInfo $file
*/
private function getLocaleFileName($file, string $locale): string
{
$relativePath = $file->getRelativePath();
$fileName = Str::before($file->getFilename(), '.');

if (! Str::is($locale, $relativePath)) {
$fileName = Str::replace('/', '.', Str::before($file->getRelativePathname(), '.'));
$fileName = Str::replace($locale . '.', '', $fileName);
}

return $fileName;
}

/**
* Create a JSON response.
*/
private function createJsonResponse(array $data): JsonResponse
{
return response()->json([
'data' => $data,
'meta' => [
'hash' => md5(json_encode($data)),
],
]);
}
}
47 changes: 38 additions & 9 deletions tests/Feature/GetLocaleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,25 @@

use Empuxa\LocaleViaApi\Controllers\GetLocaleController;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\File;

beforeEach(function () {
File::deleteDirectory(lang_path() . '/en');
File::deleteDirectory(lang_path('en'));
File::deleteDirectory(lang_path('vendor/test-plugin'));

if (! File::exists(lang_path('en'))) {
File::makeDirectory(lang_path() . '/en', 0755, true);
File::put(lang_path() . '/en/test.php', "<?php return ['title' => 'Test'];");
File::makeDirectory(lang_path('en'), 0755, true);
File::makeDirectory(lang_path('vendor/test-plugin/en'), 0755, true);

File::put(lang_path('en/test.php'), "<?php return ['title' => 'Test'];");
}
});

it('uses cache for storing locale data', function () {
$locale = 'en';

$cacheDriver = config('locale-via-api.cache.driver', 'sync');
$cacheKey = config('locale-via-api.cache.prefix') . $locale;
$cacheDriver = config('locale-via-api.cache.driver', 'array');
$cacheKey = config('locale-via-api.cache.prefix') . $locale;
$cacheDuration = config('locale-via-api.cache.duration');

Cache::shouldReceive('driver')
Expand All @@ -34,16 +38,41 @@

it('returns a json response with correct structure', function () {
$controller = new GetLocaleController;
$response = $controller('en');
$response = $controller('en');

expect($response)->toBeInstanceOf(Illuminate\Http\JsonResponse::class);

$responseData = $response->getData(true);

expect($responseData)->toHaveKeys(['data', 'meta']);

expect($responseData['data'])->toBeArray()->toBe(['test' => ['title' => 'Test']]);
expect($responseData)->toHaveKeys(['data', 'meta'])
->and($responseData['data'])->toBeArray()
->and($responseData['data'])->toBe(['test' => ['title' => 'Test']]);

$expectedHash = md5(json_encode(['test' => ['title' => 'Test']]));
expect($responseData['meta']['hash'])->toEqual($expectedHash);
});

it('returns a json response with correct structure with vendor', function () {
File::put(lang_path('vendor/test-plugin/en/vendor-test.php'), "<?php return ['title' => 'Vendor Test'];");

$controller = new GetLocaleController;
$response = $controller('en');

expect($response)->toBeInstanceOf(Illuminate\Http\JsonResponse::class);

$responseData = $response->getData(true);

expect($responseData)->toHaveKeys(['data', 'meta'])
->and($responseData['data'])->toBeArray()
->and($responseData['data'])->toHaveKey('test')
->and($responseData['data'])->toHaveKey('vendor-test')
->and($responseData['data']['test'])->toBe(['title' => 'Test'])
->and($responseData['data']['vendor-test'])->toBe(['title' => 'Vendor Test']);

$expectedHash = md5(json_encode([
'test' => ['title' => 'Test'],
'vendor-test' => ['title' => 'Vendor Test'],
]));

expect($responseData['meta']['hash'])->toEqual($expectedHash);
});

0 comments on commit 4d0ed30

Please sign in to comment.