Website/items/api/app/Data/ItemsCollection.php
2023-03-02 21:36:42 -05:00

208 lines
7.1 KiB
PHP

<?php
namespace App\Data;
use App\Exceptions\ItemNotFoundException;
use Exception;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Str;
use App\Config\GiteaConfig;
class ItemsCollection
{
protected array $items;
protected array $locales;
private string $items_file_key = 'items.json';
private string $locales_file_key = 'locales.json';
/**
* @throws Exception
*/
public function __construct()
{
if (!File::exists(storage_path($this->items_file_key))) {
$this->refreshItemsCache();
} else {
$content = file_get_contents(storage_path($this->items_file_key));
$this->items = json_decode($content, true);
}
if (!File::exists(storage_path($this->locales_file_key ))) {
$this->refreshLocalesCache();
} else {
$content = file_get_contents(storage_path($this->locales_file_key ));
$this->locales = json_decode($content, true);
}
}
/**
* @return void
* @throws Exception
*/
public function refreshLocalesCache(): void
{
$time_limit = ini_get('max_execution_time');
$memory_limit = ini_get('memory_limit');
set_time_limit(180);
ini_set('memory_limit', '256M');
$this->locales = [];
$rawLocalesGlobalBaseUrl = GiteaConfig::RAW_LOCALES_GLOBAL_BASE_URL;
// Getting all locales in project/assets/database/locales/global from the Server development branch repository
$localesList = Http::withOptions(['verify' => false])->get(GiteaConfig::LOCALES_GLOBAL_URL)->json();
foreach ($localesList as $item) {
// Extract the json name for the locale
preg_match('/([a-z]{2}(-[a-z]{2})?).json/', $item['name'], $currentLocaleName, PREG_OFFSET_CAPTURE);
// If the name is not supported for any reason, dont add it to the locales
if (empty($currentLocaleName) || !$currentLocaleName[1][0]) continue;
$trimmedCurrentLocaleName = trim($currentLocaleName[1][0]);
$currentLocaleJson = Http::withOptions(['verify' => false])
->get("$rawLocalesGlobalBaseUrl/$trimmedCurrentLocaleName.json")->json();
$templateLocale = $currentLocaleJson['templates'];
$customizationLocale = $currentLocaleJson['customization'];
$this->locales[$trimmedCurrentLocaleName] = array_merge($templateLocale, $customizationLocale);
}
if (!$handle = fopen(storage_path($this->locales_file_key ), 'w')) {
throw new Exception('Cannot open the file');
}
fwrite($handle, json_encode($this->locales));
fclose($handle);
set_time_limit($time_limit);
ini_set('memory_limit', $memory_limit);
}
/**
* @return void
* @throws Exception
*/
public function refreshItemsCache(): void
{
$time_limit = ini_get('max_execution_time');
$memory_limit = ini_get('memory_limit');
set_time_limit(180);
ini_set('memory_limit', '256M');
$items = Http::withOptions(['verify' => false])->get(GiteaConfig::RAW_ITEMS_URL)->json();
$customization = Http::withOptions(['verify' => false])->get(GiteaConfig::RAW_CUSTOMIZATION_URL)->json();
$this->items = array_merge($items, $customization);
if (!$handle = fopen(storage_path($this->items_file_key ), 'w')) {
throw new Exception('Cannot open the file');
}
fwrite($handle, json_encode($this->items));
fclose($handle);
set_time_limit($time_limit);
ini_set('memory_limit', $memory_limit);
}
/**
* @return array
*/
public function getLocales(): array
{
return array_keys($this->locales);
}
/**
* @return void
* @throws Exception
*/
public function refreshAllCache(): void
{
$this->refreshItemsCache();
$this->refreshLocalesCache();
}
/**
* Checks if the query is in the key
* @param string $key
* @param string $query
* @return bool
*/
private function contains(string $key, string $query): bool
{
$key = Str::lower(trim($key));
$query = Str::lower(trim($query));
return Str::contains($key, $query);
}
/**
* @param string $query the content of the query eg. 'AK'
* @param string $locale the chosen local. Default to 'en'
* @return Collection
*/
public function findItem(string $query, string $locale): Collection
{
$items = collect($this->items);
return $items->filter(function ($val, $key) use ($query, $locale) {
return $this->contains($val['_id'], $query)
|| $this->contains($val['_name'], $query)
|| $this->contains($val['_parent'], $query)
|| (($this->locales[$locale][$key] ?? false)
&& ($this->contains($this->locales[$locale][$key]['Name'], $query) || $this->contains($this->locales[$locale][$key]['ShortName'], $query))
);
})->map(function ($item) use ($locale) {
return [
'item' => [
'_id' => $item['_id'],
'_name' => $item['_name'],
],
'locale' => $this->locales[$locale][$item['_id']] ?? ''
];
})->values();
}
/**
* @param string $id the item ID to look for
* @param string $locale the chosen local. Default to 'en'
* @return array
* @throws ItemNotFoundException
*/
public function getItemById(string $id, string $locale): array
{
$item = $this->items[$id] ?? throw new ItemNotFoundException('Item not found');
return [
'item' => $item,
'locale' => $this->locales[$locale][$id] ?? ''
];
}
public function getHierarchy(string $id, string $locale = 'en'): Collection
{
// Return 404 if the item does not exist
$itemData = $this->items[$id] ?? throw new ItemNotFoundException('Item not found');
// Initialize the hierarchy with the current item
$item = [
'item' => [
'_id' => $itemData['_id'],
'_name' => $itemData['_name'],
'_parent' => $itemData['_parent']
],
'locale' => $this->locales[$locale][$id] ?? ''
];
$hierarchy = collect([$id => $item]);
// Check the whole hierarchy and merge into the return variable
while (!empty($item['item']['_parent'] ?? '')) {
$itemtId = $item['item']['_parent'];
$itemData = $this->items[$itemtId] ?? null;
$item = [
'item' => [
'_id' => $itemData['_id'],
'_name' => $itemData['_name'],
'_parent' => $itemData['_parent']
],
'locale' => $this->locales[$locale][$itemtId] ?? ''
];
$hierarchy = $hierarchy->merge([$itemtId => $item]);
}
return $hierarchy;
}
}