New Service: Wikidata
This commit is contained in:
parent
433e0a3199
commit
5b19490296
|
@ -137,7 +137,7 @@ public function merge(array $array)
|
||||||
*/
|
*/
|
||||||
public function get($key, $default = null)
|
public function get($key, $default = null)
|
||||||
{
|
{
|
||||||
return $this->content->get($key, $default);
|
return collect($this->content)->dot()->get($key, $default);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
92
app/Console/Commands/Wikidata/UpdateProperties.php
Normal file
92
app/Console/Commands/Wikidata/UpdateProperties.php
Normal file
|
@ -0,0 +1,92 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Console\Commands\Wikidata;
|
||||||
|
|
||||||
|
use App\Models\WikidataProperty;
|
||||||
|
use Illuminate\Console\Command;
|
||||||
|
use Illuminate\Support\Facades\Cache;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
|
use Illuminate\Support\Facades\Http;
|
||||||
|
|
||||||
|
class UpdateProperties extends Command
|
||||||
|
{
|
||||||
|
protected $signature = 'wikidata:update-properties';
|
||||||
|
|
||||||
|
protected $description = 'Import Wikidata properties into the database.';
|
||||||
|
|
||||||
|
public function handle()
|
||||||
|
{
|
||||||
|
$data = $this->fetchData();
|
||||||
|
$this->importData($data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch data from Wikidata or cache.
|
||||||
|
*/
|
||||||
|
protected function fetchData(): array
|
||||||
|
{
|
||||||
|
$endpoint = 'https://query.wikidata.org/sparql';
|
||||||
|
$query = "
|
||||||
|
SELECT ?property ?propertyType ?propertyLabel ?propertyDescription ?propertyAltLabel WHERE {
|
||||||
|
?property wikibase:propertyType ?propertyType .
|
||||||
|
SERVICE wikibase:label { bd:serviceParam wikibase:language \"fr\". }
|
||||||
|
}
|
||||||
|
ORDER BY ASC(xsd:integer(STRAFTER(STR(?property), 'P')))";
|
||||||
|
|
||||||
|
$response = Http::throw()->timeout(60)->withHeaders(['Accept' => 'application/sparql-results+json'])
|
||||||
|
->get($endpoint, ['query' => $query]);
|
||||||
|
|
||||||
|
return $response->json();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Import data into the database.
|
||||||
|
*/
|
||||||
|
protected function importData(array $data): void
|
||||||
|
{
|
||||||
|
$total = count($data['results']['bindings']);
|
||||||
|
|
||||||
|
$this->info("Starting import of $total Wikidata properties.");
|
||||||
|
|
||||||
|
$bar = $this->output->createProgressBar($total);
|
||||||
|
$bar->start();
|
||||||
|
|
||||||
|
DB::transaction(function () use ($data, &$bar) {
|
||||||
|
$batchSize = 200;
|
||||||
|
|
||||||
|
foreach (array_chunk($data['results']['bindings'], $batchSize) as $batch) {
|
||||||
|
$this->insertBatch($batch, $bar);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$bar->finish();
|
||||||
|
$this->newLine(2);
|
||||||
|
$this->info('Properties imported successfully.');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Insert a batch of properties into the database.
|
||||||
|
*
|
||||||
|
* @param \Symfony\Component\Console\Helper\ProgressBar $bar
|
||||||
|
*/
|
||||||
|
protected function insertBatch(array $batch, $bar): void
|
||||||
|
{
|
||||||
|
$upsertData = [];
|
||||||
|
|
||||||
|
foreach ($batch as $result) {
|
||||||
|
$propertyId = str_replace('http://www.wikidata.org/entity/', '', $result['property']['value']);
|
||||||
|
|
||||||
|
$upsertData[] = [
|
||||||
|
'property_id' => $propertyId,
|
||||||
|
'property_type' => $result['propertyType']['value'] ?? null,
|
||||||
|
'label' => $result['propertyLabel']['value'] ?? null,
|
||||||
|
'description' => $result['propertyDescription']['value'] ?? null,
|
||||||
|
'alt_label' => $result['propertyAltLabel']['value'] ?? null,
|
||||||
|
];
|
||||||
|
|
||||||
|
$bar->advance();
|
||||||
|
}
|
||||||
|
|
||||||
|
WikidataProperty::upsert($upsertData, 'property_id', ['property_type', 'label', 'description', 'alt_label']);
|
||||||
|
}
|
||||||
|
}
|
11
app/Models/WikidataProperty.php
Normal file
11
app/Models/WikidataProperty.php
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class WikidataProperty extends Model
|
||||||
|
{
|
||||||
|
use HasFactory;
|
||||||
|
}
|
37
app/Providers/WikidataServiceProvider.php
Normal file
37
app/Providers/WikidataServiceProvider.php
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Providers;
|
||||||
|
|
||||||
|
use App\Services\Wikidata\WikidataClient;
|
||||||
|
use App\Services\Wikidata\WikidataExtractor;
|
||||||
|
use Illuminate\Support\ServiceProvider;
|
||||||
|
|
||||||
|
class WikidataServiceProvider extends ServiceProvider
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Register services.
|
||||||
|
*/
|
||||||
|
public function register(): void
|
||||||
|
{
|
||||||
|
$this->app->singleton(WikidataClient::class, function ($app) {
|
||||||
|
$config = $app['config']->get('services.wikidata');
|
||||||
|
|
||||||
|
return new WikidataClient($config);
|
||||||
|
});
|
||||||
|
|
||||||
|
$this->app->singleton(WikidataExtractor::class, function ($app) {
|
||||||
|
$inclusions = $app['config']->get('wikidata.inclusions', []);
|
||||||
|
$exclusions = $app['config']->get('wikidata.exclusions', []);
|
||||||
|
|
||||||
|
return new WikidataExtractor($exclusions, $inclusions);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bootstrap services.
|
||||||
|
*/
|
||||||
|
public function boot(): void
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,8 +3,14 @@
|
||||||
namespace App\Services\BundleCreator\Creators;
|
namespace App\Services\BundleCreator\Creators;
|
||||||
|
|
||||||
use App\Classes\Bundle;
|
use App\Classes\Bundle;
|
||||||
|
use App\Exceptions\BundleAlreadyExists;
|
||||||
|
use App\Services\Wikidata\WikidataClient;
|
||||||
|
use App\Services\Wikidata\WikidataExtractor;
|
||||||
|
use Exception;
|
||||||
use Illuminate\Filesystem\FilesystemAdapter;
|
use Illuminate\Filesystem\FilesystemAdapter;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
|
||||||
|
use function Laravel\Prompts\confirm;
|
||||||
use function Laravel\Prompts\select;
|
use function Laravel\Prompts\select;
|
||||||
use function Laravel\Prompts\text;
|
use function Laravel\Prompts\text;
|
||||||
|
|
||||||
|
@ -17,6 +23,63 @@ public function __construct(protected ?array $data, protected FilesystemAdapter
|
||||||
//
|
//
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a bundle
|
||||||
|
*/
|
||||||
|
public function createBundle(): string
|
||||||
|
{
|
||||||
|
$entityId = $this->data['entity_id'];
|
||||||
|
|
||||||
|
if ($entityId === false) {
|
||||||
|
throw new Exception('Bundle creation cancelled');
|
||||||
|
}
|
||||||
|
|
||||||
|
$kind = $this->data['kind'];
|
||||||
|
$title = $this->data['title'];
|
||||||
|
$slug = Str::slug($title);
|
||||||
|
$date = now();
|
||||||
|
$path = sprintf('%s/%s/%s', static::$section, $kind, $slug);
|
||||||
|
$bundle = new Bundle($path, $this->disk);
|
||||||
|
|
||||||
|
if ($bundle->exists()) {
|
||||||
|
throw new BundleAlreadyExists(
|
||||||
|
sprintf('A bundle already exists in %s', $path)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$wikidata = app()->make(WikidataClient::class);
|
||||||
|
$extractor = app()->make(WikidataExtractor::class);
|
||||||
|
$completeEntity = $wikidata->getEntityData($entityId, true)['entities'][$entityId];
|
||||||
|
|
||||||
|
$extractor->extract($completeEntity, $entityId);
|
||||||
|
|
||||||
|
$bundle->metadata('wikidata/included')->setMany($extractor->included());
|
||||||
|
$bundle->metadata('wikidata/excluded')->setMany($extractor->excluded());
|
||||||
|
$bundle->metadata('wikidata/unused')->setMany($extractor->unused());
|
||||||
|
$bundle->metadata('wikidata/entity')->setMany($extractor->everythingElse());
|
||||||
|
|
||||||
|
$frenchTitle = $bundle->metadata('wikidata/entity')->get('labels.fr.value', null);
|
||||||
|
$originalTitle = $bundle->metadata('wikidata/entity')->get('labels.en.value', null);
|
||||||
|
|
||||||
|
if (!empty($originalTitle)) {
|
||||||
|
$bundle->metadata()->set('title', $originalTitle);
|
||||||
|
|
||||||
|
if (!empty($frenchTitle) && $frenchTitle !== $originalTitle) {
|
||||||
|
$bundle->metadata()->set('subTitle', $frenchTitle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$bundle->metadata()->setMany([
|
||||||
|
'date' => $date->toIso8601String(),
|
||||||
|
]);
|
||||||
|
|
||||||
|
$bundle->markdown()->set('');
|
||||||
|
|
||||||
|
$bundle->save();
|
||||||
|
|
||||||
|
return $path;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return a boolean value indicating if the creator can actually make the
|
* Return a boolean value indicating if the creator can actually make the
|
||||||
* bundle using known data.
|
* bundle using known data.
|
||||||
|
@ -26,7 +89,7 @@ public function canCreateBundle(): bool
|
||||||
return
|
return
|
||||||
!empty($this->data['kind'])
|
!empty($this->data['kind'])
|
||||||
&& !empty($this->data['title'])
|
&& !empty($this->data['title'])
|
||||||
&& !empty($this->data['entityId']);
|
&& array_key_exists('entity_id', $this->data);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -45,8 +108,16 @@ public function formSpecs(): ?array
|
||||||
$specs['title'] = fn () => text('Work title', '', '', true);
|
$specs['title'] = fn () => text('Work title', '', '', true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (empty($this->data['entityId'])) {
|
if (!empty($this->data['kind']) && !empty($this->data['title']) && empty($this->data['entity_id'])) {
|
||||||
$specs['entityId'] = fn () => text('Entity ID', '', '', true);
|
$options = app()->make(WikidataClient::class)->searchEntityId($this->data['title']);
|
||||||
|
|
||||||
|
if (!empty($options)) {
|
||||||
|
$specs['entity_id'] = fn () => select('Confirm searched work', $options);
|
||||||
|
} else {
|
||||||
|
$specs['entity_id'] = fn () => confirm(
|
||||||
|
'No entityId was found in Wikidata for this work. Do you want to create the bundle anyway?'
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $specs;
|
return $specs;
|
||||||
|
|
132
app/Services/Wikidata/WikidataClient.php
Normal file
132
app/Services/Wikidata/WikidataClient.php
Normal file
|
@ -0,0 +1,132 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Services\Wikidata;
|
||||||
|
|
||||||
|
use Illuminate\Support\Facades\Cache;
|
||||||
|
use Illuminate\Support\Facades\Http;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
|
||||||
|
class WikidataClient
|
||||||
|
{
|
||||||
|
protected static string $cachePrefix = 'wikidata';
|
||||||
|
|
||||||
|
public function __construct(protected array $config)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Search for an entity ID for text submitted as $expression
|
||||||
|
*/
|
||||||
|
public function searchEntityId(string $expression)
|
||||||
|
{
|
||||||
|
$data = [
|
||||||
|
'action' => 'wbsearchentities',
|
||||||
|
'search' => $expression,
|
||||||
|
'language' => 'en',
|
||||||
|
'limit' => 10,
|
||||||
|
'format' => 'json',
|
||||||
|
];
|
||||||
|
|
||||||
|
$response = $this->getFromApi($data);
|
||||||
|
$items = [];
|
||||||
|
|
||||||
|
if (!empty($response['search'])) {
|
||||||
|
foreach ($response['search'] as $item) {
|
||||||
|
$items[$item['id']] = sprintf('[%s] %s (%s)', $item['id'], $item['label'], $item['description'] ?? null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $items;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return complete set of data related to specified entity
|
||||||
|
*/
|
||||||
|
public function getEntityData(string $entityId)
|
||||||
|
{
|
||||||
|
$data = [
|
||||||
|
'action' => 'wbgetentities',
|
||||||
|
'ids' => $entityId,
|
||||||
|
'languages' => 'fr|en',
|
||||||
|
'format' => 'json',
|
||||||
|
];
|
||||||
|
|
||||||
|
return $this->getFromApi($data);
|
||||||
|
|
||||||
|
// if ($replaceIds) {
|
||||||
|
// $data = json_encode($result, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
|
||||||
|
// $properties = $this->getDeclaredPropertiesInEntity($data);
|
||||||
|
// $entities = $this->getDeclaredEntitiesInEntity($data, $entityId);
|
||||||
|
// $result = $this->replaceLabelsIn($result, $properties, $entities, $entityId);
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return an array containing Wikidata Entities Id as keys and corresponding
|
||||||
|
* labels as values
|
||||||
|
*/
|
||||||
|
public function getLabelsForEntities(array $entities)
|
||||||
|
{
|
||||||
|
$result = [];
|
||||||
|
$batchSize = 50;
|
||||||
|
$batches = array_chunk($entities, $batchSize);
|
||||||
|
|
||||||
|
foreach ($batches as $batch) {
|
||||||
|
$ids = implode('|', $batch);
|
||||||
|
$data = [
|
||||||
|
'action' => 'wbgetentities',
|
||||||
|
'ids' => $ids,
|
||||||
|
'props' => 'labels|descriptions',
|
||||||
|
'languages' => 'fr|en',
|
||||||
|
'format' => 'json',
|
||||||
|
];
|
||||||
|
|
||||||
|
$result += $this->getFromApi($data)['entities'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$labels = [];
|
||||||
|
|
||||||
|
foreach ($result as $id => $entity) {
|
||||||
|
if (
|
||||||
|
!isset($entity['labels']['fr']['value'])
|
||||||
|
&& !isset($entity['labels']['en']['value'])
|
||||||
|
) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$label = $entity['labels']['fr']['value']
|
||||||
|
?? $entity['labels']['en']['value'];
|
||||||
|
|
||||||
|
$description = $entity['descriptions']['fr']['value']
|
||||||
|
?? $entity['descriptions']['en']['value']
|
||||||
|
?? null;
|
||||||
|
|
||||||
|
if ($label) {
|
||||||
|
$labels[$id] = Str::ucfirst($label);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $labels;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform a GET request against wikidata API
|
||||||
|
*/
|
||||||
|
private function getFromApi(array $params)
|
||||||
|
{
|
||||||
|
$baseUrl = $this->config['baseApiUrl'];
|
||||||
|
$slug = Str::slug(http_build_query($params));
|
||||||
|
$cacheKey = sprintf('%s_%s', static::$cachePrefix, $slug);
|
||||||
|
|
||||||
|
if (Cache::has($cacheKey)) {
|
||||||
|
return Cache::get($cacheKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
$response = Http::throw()->get($baseUrl, $params)->json();
|
||||||
|
|
||||||
|
Cache::put($cacheKey, $response, now()->addMonth());
|
||||||
|
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
}
|
308
app/Services/Wikidata/WikidataExtractor.php
Normal file
308
app/Services/Wikidata/WikidataExtractor.php
Normal file
|
@ -0,0 +1,308 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Services\Wikidata;
|
||||||
|
|
||||||
|
use App\Models\WikidataProperty;
|
||||||
|
|
||||||
|
class WikidataExtractor
|
||||||
|
{
|
||||||
|
protected array $included;
|
||||||
|
|
||||||
|
protected array $excluded;
|
||||||
|
|
||||||
|
protected array $unused;
|
||||||
|
|
||||||
|
protected array $everythingElse;
|
||||||
|
|
||||||
|
protected string $entityId;
|
||||||
|
|
||||||
|
protected $properties;
|
||||||
|
|
||||||
|
protected $entities;
|
||||||
|
|
||||||
|
public function included()
|
||||||
|
{
|
||||||
|
return $this->included;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function excluded()
|
||||||
|
{
|
||||||
|
return $this->excluded;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function unused()
|
||||||
|
{
|
||||||
|
return $this->unused;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function everythingElse()
|
||||||
|
{
|
||||||
|
return $this->everythingElse;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __construct(protected array $exclusions, protected array $inclusions)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Split data from specified array in three arrays containing explicitely
|
||||||
|
* included properties, explicitely excluded properties and unused
|
||||||
|
* properties (neither included or excluded)
|
||||||
|
*/
|
||||||
|
public function extract(array $entityData, string $entityId)
|
||||||
|
{
|
||||||
|
$json = json_encode($entityData, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
|
||||||
|
|
||||||
|
$this->properties = $this->getDeclaredPropertiesInEntity($json);
|
||||||
|
$this->entities = $this->getDeclaredEntitiesInEntity($json, $entityId);
|
||||||
|
|
||||||
|
$result = $this->browse($entityData['claims']);
|
||||||
|
|
||||||
|
$this->included = $result['included'];
|
||||||
|
$this->excluded = $result['excluded'];
|
||||||
|
$this->unused = $result['unused'];
|
||||||
|
|
||||||
|
unset($entityData['claims']);
|
||||||
|
|
||||||
|
$this->everythingElse = $entityData;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return an array containing Wikidata Property ID as keys and corresponding
|
||||||
|
* label as values
|
||||||
|
*/
|
||||||
|
private function getDeclaredPropertiesInEntity(string $data)
|
||||||
|
{
|
||||||
|
preg_match_all('/P\d{1,}/', $data, $matches);
|
||||||
|
natsort($matches[0]);
|
||||||
|
|
||||||
|
$ids = collect(array_values($matches[0]))->unique()->all();
|
||||||
|
$properties = WikidataProperty::whereIn('property_id', $ids)->get();
|
||||||
|
$result = collect($ids)->combine($properties->pluck('label'));
|
||||||
|
|
||||||
|
return $result->toArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return an array containing Wikidata Property ID as keys and corresponding
|
||||||
|
* label as values
|
||||||
|
*/
|
||||||
|
private function getDeclaredEntitiesInEntity(string $data, string $entityId)
|
||||||
|
{
|
||||||
|
preg_match_all('/Q\d{1,}/', $data, $matches);
|
||||||
|
natsort($matches[0]);
|
||||||
|
|
||||||
|
$ids = collect(array_values($matches[0]))->except($entityId)->unique()->all();
|
||||||
|
|
||||||
|
return app()->make(WikidataClient::class)->getLabelsForEntities($ids);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Recursively browse Wikidata array
|
||||||
|
*/
|
||||||
|
private function browse(array $claims)
|
||||||
|
{
|
||||||
|
$included = [];
|
||||||
|
$excluded = [];
|
||||||
|
$unused = [];
|
||||||
|
|
||||||
|
foreach ($claims as $key => $data) {
|
||||||
|
$isExcluded = in_array($key, $this->exclusions);
|
||||||
|
$isIncluded = in_array($key, collect($this->inclusions)->flatten()->values()->toArray());
|
||||||
|
$isUnused = !$isExcluded && !$isIncluded;
|
||||||
|
|
||||||
|
$claim = $this->parseClaims($data, $isIncluded);
|
||||||
|
|
||||||
|
if ($isExcluded) {
|
||||||
|
$newKey = $this->replaceValue($key, true, true);
|
||||||
|
$excluded[$newKey] = $claim;
|
||||||
|
} elseif ($isIncluded) {
|
||||||
|
$newKey = $this->replaceValue($key, true);
|
||||||
|
$included[$key] = $claim;
|
||||||
|
} elseif ($isUnused) {
|
||||||
|
$newKey = $this->replaceValue($key, true, true);
|
||||||
|
$unused[$newKey] = $claim;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
'excluded' => $excluded,
|
||||||
|
'included' => $this->reorganizeIncluded($included),
|
||||||
|
'unused' => $unused,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse claims of a specific property
|
||||||
|
*/
|
||||||
|
private function parseClaims(array $data, bool $parentIncluded)
|
||||||
|
{
|
||||||
|
$result = [];
|
||||||
|
|
||||||
|
foreach ($data as $claim) {
|
||||||
|
$result[] = $this->parseClaim($claim, $parentIncluded);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse a specific claim
|
||||||
|
*/
|
||||||
|
private function parseClaim(array $data, bool $parentIncluded)
|
||||||
|
{
|
||||||
|
$value = $this->parseSnak($data['mainsnak'], $parentIncluded);
|
||||||
|
|
||||||
|
if (!empty($data['qualifiers'])) {
|
||||||
|
$itemQualifiers = [];
|
||||||
|
|
||||||
|
foreach ($data['qualifiers'] as $qualifierProperty => $qualifiers) {
|
||||||
|
$qualifierKey = $this->replaceValue($qualifierProperty, true, !$parentIncluded);
|
||||||
|
|
||||||
|
foreach ($qualifiers as $qualifierData) {
|
||||||
|
$qualifierValue = $this->parseSnak($qualifierData, $parentIncluded);
|
||||||
|
|
||||||
|
$itemQualifiers[$qualifierKey][] = $qualifierValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$result = [
|
||||||
|
$value => $itemQualifiers,
|
||||||
|
];
|
||||||
|
} else {
|
||||||
|
$result = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse a specific snak
|
||||||
|
*/
|
||||||
|
private function parseSnak(array $data, bool $parentIncluded)
|
||||||
|
{
|
||||||
|
if (empty($data['datavalue']['value'])) {
|
||||||
|
dd($data);
|
||||||
|
}
|
||||||
|
|
||||||
|
$value = $data['datavalue']['value'];
|
||||||
|
$valueType = $data['datavalue']['type'];
|
||||||
|
|
||||||
|
switch ($valueType) {
|
||||||
|
case 'wikibase-entityid':
|
||||||
|
$value = $this->replaceValue($value['id'], true, !$parentIncluded);
|
||||||
|
break;
|
||||||
|
case 'string':
|
||||||
|
$value = $this->replaceValue($value, true, !$parentIncluded);
|
||||||
|
break;
|
||||||
|
case 'time':
|
||||||
|
$value = $value['time'];
|
||||||
|
break;
|
||||||
|
case 'quantity':
|
||||||
|
$value = $value['amount'];
|
||||||
|
break;
|
||||||
|
case 'monolingualtext':
|
||||||
|
$value = $value['text'];
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
dd($data['mainsnak']);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Replace a value with a more human-friendly version. Basically replaces
|
||||||
|
* Wikidata entities and properties with labels stored in database, if it
|
||||||
|
* applies.
|
||||||
|
*/
|
||||||
|
private function replaceValue(string $value, bool $showCode = true, bool $showLabel = true)
|
||||||
|
{
|
||||||
|
$isExcluded = in_array($value, $this->exclusions);
|
||||||
|
$isIncluded = in_array($value, collect($this->inclusions)->flatten()->values()->toArray());
|
||||||
|
$isUnused = !$isExcluded && !$isIncluded;
|
||||||
|
|
||||||
|
$code = $value;
|
||||||
|
$label = $value;
|
||||||
|
|
||||||
|
if (array_key_exists($value, $this->properties)) {
|
||||||
|
$label = $this->properties[$value];
|
||||||
|
} elseif (array_key_exists($value, $this->entities)) {
|
||||||
|
$label = $this->entities[$value];
|
||||||
|
}
|
||||||
|
|
||||||
|
$both = $code !== $label ? sprintf('[%s] %s', $code, $label) : $value;
|
||||||
|
|
||||||
|
if ($showCode && $showLabel) {
|
||||||
|
return $both;
|
||||||
|
} elseif ($showCode) {
|
||||||
|
return $code;
|
||||||
|
} else {
|
||||||
|
return $label;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Take the "raw" included data and reorganize it according to the
|
||||||
|
* "inclusions" Wikidata configuration
|
||||||
|
*/
|
||||||
|
private function reorganizeIncluded(array $includedData)
|
||||||
|
{
|
||||||
|
$reorganized = [];
|
||||||
|
|
||||||
|
foreach ($this->inclusions as $category => $properties) {
|
||||||
|
$result = $this->includeProperties($includedData, $properties);
|
||||||
|
|
||||||
|
if (!empty($result)) {
|
||||||
|
$reorganized[$category] = $result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $reorganized;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Include specific properties
|
||||||
|
*/
|
||||||
|
private function includeProperties($includedData, $properties)
|
||||||
|
{
|
||||||
|
$result = [];
|
||||||
|
|
||||||
|
foreach ($properties as $propertyId) {
|
||||||
|
if (!array_key_exists($propertyId, $includedData)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$newKey = $this->replaceValue($propertyId, false, true);
|
||||||
|
|
||||||
|
$values = $includedData[$propertyId];
|
||||||
|
|
||||||
|
$result[$newKey] = $this->includeValues($values);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Include specific values
|
||||||
|
*/
|
||||||
|
private function includeValues(array $values)
|
||||||
|
{
|
||||||
|
$newValues = [];
|
||||||
|
|
||||||
|
foreach ($values as $key => $value) {
|
||||||
|
$newKey = $this->replaceValue($key, false, true);
|
||||||
|
|
||||||
|
if (is_array($value)) {
|
||||||
|
$value = $this->includeValues($value);
|
||||||
|
} else {
|
||||||
|
$value = $this->replaceValue($value, false, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
$newValues[$newKey] = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $newValues;
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,4 +4,5 @@
|
||||||
App\Providers\AppServiceProvider::class,
|
App\Providers\AppServiceProvider::class,
|
||||||
App\Providers\BundleCreatorServiceProvider::class,
|
App\Providers\BundleCreatorServiceProvider::class,
|
||||||
App\Providers\RebrickableServiceProvider::class,
|
App\Providers\RebrickableServiceProvider::class,
|
||||||
|
App\Providers\WikidataServiceProvider::class,
|
||||||
];
|
];
|
||||||
|
|
|
@ -19,6 +19,10 @@
|
||||||
'key' => env('REBRICKABLE_API_KEY'),
|
'key' => env('REBRICKABLE_API_KEY'),
|
||||||
],
|
],
|
||||||
|
|
||||||
|
'wikidata' => [
|
||||||
|
'baseApiUrl' => 'https://www.wikidata.org/w/api.php',
|
||||||
|
],
|
||||||
|
|
||||||
'postmark' => [
|
'postmark' => [
|
||||||
'token' => env('POSTMARK_TOKEN'),
|
'token' => env('POSTMARK_TOKEN'),
|
||||||
],
|
],
|
||||||
|
|
234
config/wikidata/exclusions.php
Normal file
234
config/wikidata/exclusions.php
Normal file
|
@ -0,0 +1,234 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
return [
|
||||||
|
'P18',
|
||||||
|
'P31',
|
||||||
|
'P214',
|
||||||
|
'P227',
|
||||||
|
'P244',
|
||||||
|
'P268',
|
||||||
|
'P269',
|
||||||
|
'P373',
|
||||||
|
'P434',
|
||||||
|
'P436',
|
||||||
|
'P437',
|
||||||
|
'P444',
|
||||||
|
'P462',
|
||||||
|
'P480',
|
||||||
|
'P527',
|
||||||
|
'P580',
|
||||||
|
'P582',
|
||||||
|
'P646',
|
||||||
|
'P674',
|
||||||
|
'P691',
|
||||||
|
'P905',
|
||||||
|
'P950',
|
||||||
|
'P973',
|
||||||
|
'P1015',
|
||||||
|
'P1110',
|
||||||
|
'P1237',
|
||||||
|
'P1343',
|
||||||
|
'P1407',
|
||||||
|
'P1417',
|
||||||
|
'P1424',
|
||||||
|
'P1562',
|
||||||
|
'P1617',
|
||||||
|
'P1657',
|
||||||
|
'P1695',
|
||||||
|
'P1804',
|
||||||
|
'P1889',
|
||||||
|
'P1933',
|
||||||
|
'P1970',
|
||||||
|
'P1981',
|
||||||
|
'P2047',
|
||||||
|
'P2061',
|
||||||
|
'P2130',
|
||||||
|
'P2142',
|
||||||
|
'P2163',
|
||||||
|
'P2334',
|
||||||
|
'P2346',
|
||||||
|
'P2363',
|
||||||
|
'P2465',
|
||||||
|
'P2508',
|
||||||
|
'P2509',
|
||||||
|
'P2518',
|
||||||
|
'P2529',
|
||||||
|
'P2572',
|
||||||
|
'P2581',
|
||||||
|
'P2603',
|
||||||
|
'P2629',
|
||||||
|
'P2631',
|
||||||
|
'P2636',
|
||||||
|
'P2637',
|
||||||
|
'P2638',
|
||||||
|
'P2671',
|
||||||
|
'P2684',
|
||||||
|
'P2703',
|
||||||
|
'P2704',
|
||||||
|
'P2747',
|
||||||
|
'P2755',
|
||||||
|
'P2756',
|
||||||
|
'P2758',
|
||||||
|
'P2769',
|
||||||
|
'P2899',
|
||||||
|
'P3077',
|
||||||
|
'P3107',
|
||||||
|
'P3110',
|
||||||
|
'P3121',
|
||||||
|
'P3129',
|
||||||
|
'P3135',
|
||||||
|
'P3138',
|
||||||
|
'P3141',
|
||||||
|
'P3143',
|
||||||
|
'P3145',
|
||||||
|
'P3156',
|
||||||
|
'P3203',
|
||||||
|
'P3212',
|
||||||
|
'P3216',
|
||||||
|
'P3222',
|
||||||
|
'P3306',
|
||||||
|
'P3402',
|
||||||
|
'P3417',
|
||||||
|
'P3428',
|
||||||
|
'P3478',
|
||||||
|
'P3553',
|
||||||
|
'P3593',
|
||||||
|
'P3650',
|
||||||
|
'P3803',
|
||||||
|
'P3804',
|
||||||
|
'P3808',
|
||||||
|
'P3834',
|
||||||
|
'P3844',
|
||||||
|
'P3854',
|
||||||
|
'P3933',
|
||||||
|
'P4276',
|
||||||
|
'P4277',
|
||||||
|
'P4282',
|
||||||
|
'P4312',
|
||||||
|
'P4342',
|
||||||
|
'P4437',
|
||||||
|
'P4438',
|
||||||
|
'P4784',
|
||||||
|
'P4835',
|
||||||
|
'P4515',
|
||||||
|
'P4529',
|
||||||
|
'P4632',
|
||||||
|
'P4665',
|
||||||
|
'P4780',
|
||||||
|
'P4783',
|
||||||
|
'P4786',
|
||||||
|
'P4834',
|
||||||
|
'P4839',
|
||||||
|
'P5021',
|
||||||
|
'P5032',
|
||||||
|
'P5099',
|
||||||
|
'P5128',
|
||||||
|
'P5150',
|
||||||
|
'P5201',
|
||||||
|
'P5255',
|
||||||
|
'P5253',
|
||||||
|
'P5311',
|
||||||
|
'P5327',
|
||||||
|
'P5357',
|
||||||
|
'P5387',
|
||||||
|
'P5495',
|
||||||
|
'P5693',
|
||||||
|
'P5786',
|
||||||
|
'P5829',
|
||||||
|
'P5845',
|
||||||
|
'P5865',
|
||||||
|
'P5885',
|
||||||
|
'P5905',
|
||||||
|
'P5925',
|
||||||
|
'P5970',
|
||||||
|
'P5987',
|
||||||
|
'P5990',
|
||||||
|
'P6058',
|
||||||
|
'P6081',
|
||||||
|
'P6104',
|
||||||
|
'P6127',
|
||||||
|
'P6133',
|
||||||
|
'P6145',
|
||||||
|
'P6181',
|
||||||
|
'P6466',
|
||||||
|
'P6467',
|
||||||
|
'P6562',
|
||||||
|
'P6584',
|
||||||
|
'P6643',
|
||||||
|
'P6658',
|
||||||
|
'P6760',
|
||||||
|
'P6839',
|
||||||
|
'P7003',
|
||||||
|
'P7091',
|
||||||
|
'P7107',
|
||||||
|
'P7118',
|
||||||
|
'P7132',
|
||||||
|
'P7236',
|
||||||
|
'P7285',
|
||||||
|
'P7293',
|
||||||
|
'P7299',
|
||||||
|
'P7334',
|
||||||
|
'P7501',
|
||||||
|
'P7502',
|
||||||
|
'P7573',
|
||||||
|
'P7777',
|
||||||
|
'P7822',
|
||||||
|
'P7970',
|
||||||
|
'P7975',
|
||||||
|
'P7978',
|
||||||
|
'P8013',
|
||||||
|
'P8033',
|
||||||
|
'P8179',
|
||||||
|
'P8189',
|
||||||
|
'P8278',
|
||||||
|
'P8313',
|
||||||
|
'P8419',
|
||||||
|
'P8600',
|
||||||
|
'P8687',
|
||||||
|
'P8796',
|
||||||
|
'P8823',
|
||||||
|
'P8847',
|
||||||
|
'P8874',
|
||||||
|
'P8885',
|
||||||
|
'P8889',
|
||||||
|
'P8958',
|
||||||
|
'P9022',
|
||||||
|
'P9086',
|
||||||
|
'P9629',
|
||||||
|
'P9697',
|
||||||
|
'P9821',
|
||||||
|
'P9885',
|
||||||
|
'P9984',
|
||||||
|
'P9979',
|
||||||
|
'P10045',
|
||||||
|
'P10096',
|
||||||
|
'P10164',
|
||||||
|
'P10167',
|
||||||
|
'P10239',
|
||||||
|
'P10255',
|
||||||
|
'P10267',
|
||||||
|
'P10269',
|
||||||
|
'P10291',
|
||||||
|
'P10432',
|
||||||
|
'P10565',
|
||||||
|
'P10688',
|
||||||
|
'P10845',
|
||||||
|
'P11196',
|
||||||
|
'P11346',
|
||||||
|
'P11408',
|
||||||
|
'P11505',
|
||||||
|
'P11514',
|
||||||
|
'P11682',
|
||||||
|
'P11686',
|
||||||
|
'P11871',
|
||||||
|
'P11948',
|
||||||
|
'P12035',
|
||||||
|
'P12086',
|
||||||
|
'P12096',
|
||||||
|
'P12159',
|
||||||
|
'P12196',
|
||||||
|
'P12241',
|
||||||
|
'P12329',
|
||||||
|
'P12492',
|
||||||
|
'P12544',
|
||||||
|
];
|
82
config/wikidata/inclusions.php
Normal file
82
config/wikidata/inclusions.php
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
return [
|
||||||
|
'afterWorkBy' => [
|
||||||
|
'P1877',
|
||||||
|
],
|
||||||
|
'staff' => [
|
||||||
|
'P50',
|
||||||
|
'P57',
|
||||||
|
'P58',
|
||||||
|
'P86',
|
||||||
|
'P162',
|
||||||
|
'P170',
|
||||||
|
'P175',
|
||||||
|
'P178',
|
||||||
|
'P344',
|
||||||
|
'P371',
|
||||||
|
'P1040',
|
||||||
|
'P1431',
|
||||||
|
'P2515',
|
||||||
|
'P2554',
|
||||||
|
'P3092',
|
||||||
|
'P5028',
|
||||||
|
],
|
||||||
|
'productionCompanies' => [
|
||||||
|
'P272',
|
||||||
|
],
|
||||||
|
'genres' => [
|
||||||
|
'P136',
|
||||||
|
],
|
||||||
|
'subjects' => [
|
||||||
|
'P921',
|
||||||
|
],
|
||||||
|
'publishers' => [
|
||||||
|
'P123',
|
||||||
|
],
|
||||||
|
'distribution' => [
|
||||||
|
'P161',
|
||||||
|
],
|
||||||
|
'sagas' => [
|
||||||
|
'P179',
|
||||||
|
],
|
||||||
|
'links' => [
|
||||||
|
'P856',
|
||||||
|
'P345',
|
||||||
|
'P1258',
|
||||||
|
'P1265',
|
||||||
|
'P1267',
|
||||||
|
'P1651',
|
||||||
|
'P1712',
|
||||||
|
'P1733',
|
||||||
|
'P1874',
|
||||||
|
'P2002',
|
||||||
|
'P2003',
|
||||||
|
'P2013',
|
||||||
|
'P2397',
|
||||||
|
'P3984',
|
||||||
|
'P4013',
|
||||||
|
'P4073',
|
||||||
|
'P4477',
|
||||||
|
'P4947',
|
||||||
|
'P4983',
|
||||||
|
'P5749',
|
||||||
|
'P6262',
|
||||||
|
'P6398',
|
||||||
|
'P7595',
|
||||||
|
'P7596',
|
||||||
|
'P8055',
|
||||||
|
'P9586',
|
||||||
|
'P9751',
|
||||||
|
'P11460',
|
||||||
|
],
|
||||||
|
'locations' => [
|
||||||
|
'P840',
|
||||||
|
'P915',
|
||||||
|
],
|
||||||
|
'miscKeywords' => [
|
||||||
|
'P180',
|
||||||
|
'P8371',
|
||||||
|
'P8411',
|
||||||
|
],
|
||||||
|
];
|
118
config/wikidata/templates.php
Normal file
118
config/wikidata/templates.php
Normal file
|
@ -0,0 +1,118 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
return [
|
||||||
|
'links' => [
|
||||||
|
'P856' => [
|
||||||
|
'template' => null,
|
||||||
|
'title' => 'Site officiel',
|
||||||
|
],
|
||||||
|
'P345' => [
|
||||||
|
'template' => 'https://www.imdb.com/title/%s/',
|
||||||
|
'title' => 'IMDB',
|
||||||
|
],
|
||||||
|
'P1258' => [
|
||||||
|
'template' => 'https://www.rottentomatoes.com/%s',
|
||||||
|
'title' => 'Rotten Tomatoes',
|
||||||
|
],
|
||||||
|
'P1265' => [
|
||||||
|
'template' => 'https://www.allocine.fr/film/fichefilm_gen_cfilm=%s.html',
|
||||||
|
'title' => 'AlloCiné',
|
||||||
|
],
|
||||||
|
'P1267' => [
|
||||||
|
'template' => 'https://www.allocine.fr/series/ficheserie_gen_cserie=%s.html',
|
||||||
|
'title' => 'AlloCiné',
|
||||||
|
],
|
||||||
|
'P1651' => [
|
||||||
|
'template' => 'https://www.youtube.com/watch?v=%s',
|
||||||
|
'title' => 'YouTube',
|
||||||
|
],
|
||||||
|
'P1712' => [
|
||||||
|
'template' => 'https://www.metacritic.com/%s',
|
||||||
|
'title' => 'Metacritic',
|
||||||
|
],
|
||||||
|
'P1733' => [
|
||||||
|
'template' => 'https://store.steampowered.com/app/%s/',
|
||||||
|
'title' => 'Steam',
|
||||||
|
],
|
||||||
|
'P1874' => [
|
||||||
|
'template' => 'https://www.netflix.com/title/%s',
|
||||||
|
'title' => 'Netflix',
|
||||||
|
],
|
||||||
|
'P2002' => [
|
||||||
|
'template' => 'https://twitter.com/%s',
|
||||||
|
'title' => 'X',
|
||||||
|
],
|
||||||
|
'P2003' => [
|
||||||
|
'template' => 'https://www.instagram.com/%s',
|
||||||
|
'title' => 'Instagram',
|
||||||
|
],
|
||||||
|
'P2013' => [
|
||||||
|
'template' => 'https://www.facebook.com/%s',
|
||||||
|
'title' => 'facebook',
|
||||||
|
],
|
||||||
|
'P2397' => [
|
||||||
|
'template' => 'https://www.youtube.com/channel/%s',
|
||||||
|
'title' => 'Chaîne YouTube',
|
||||||
|
],
|
||||||
|
'P3984' => [
|
||||||
|
'template' => 'https://www.reddit.com/r/%s/',
|
||||||
|
'title' => 'Reddit',
|
||||||
|
],
|
||||||
|
'P4013' => [
|
||||||
|
'template' => 'https://giphy.com/%s',
|
||||||
|
'title' => 'Giphy',
|
||||||
|
],
|
||||||
|
'P4073' => [
|
||||||
|
'template' => 'https://community.fandom.com/wiki/w:c:%s',
|
||||||
|
'title' => 'Fandom',
|
||||||
|
],
|
||||||
|
'P4477' => [
|
||||||
|
'template' => 'https://www.humblebundle.com/store/%s',
|
||||||
|
'title' => 'Humble Store',
|
||||||
|
],
|
||||||
|
'P4947' => [
|
||||||
|
'template' => 'https://www.themoviedb.org/movie/%s',
|
||||||
|
'title' => 'TMDB',
|
||||||
|
],
|
||||||
|
'P4983' => [
|
||||||
|
'template' => 'https://www.themoviedb.org/tv/%s',
|
||||||
|
'title' => 'TMBD',
|
||||||
|
],
|
||||||
|
'P5749' => [
|
||||||
|
'template' => 'https://www.amazon.com/dp/%s',
|
||||||
|
'title' => 'Amazon',
|
||||||
|
],
|
||||||
|
'P6262' => [
|
||||||
|
'template' => 'https://community.fandom.com/wiki/w:c:%s',
|
||||||
|
'title' => 'Fandom',
|
||||||
|
],
|
||||||
|
'P6398' => [
|
||||||
|
'template' => 'https://itunes.apple.com/us/movie/id%s',
|
||||||
|
'title' => 'iTunes',
|
||||||
|
],
|
||||||
|
'P7595' => [
|
||||||
|
'template' => 'https://www.disneyplus.com/movies/wd/%s',
|
||||||
|
'title' => 'Disney+',
|
||||||
|
],
|
||||||
|
'P7596' => [
|
||||||
|
'template' => 'https://www.disneyplus.com/series/wp/%s',
|
||||||
|
'title' => 'Disney+',
|
||||||
|
],
|
||||||
|
'P8055' => [
|
||||||
|
'template' => 'https://www.amazon.com/gp/video/detail/%s',
|
||||||
|
'title' => 'Amazon Prime',
|
||||||
|
],
|
||||||
|
'P9586' => [
|
||||||
|
'template' => 'https://tv.apple.com/movie/%s',
|
||||||
|
'title' => 'Apple TV',
|
||||||
|
],
|
||||||
|
'P9751' => [
|
||||||
|
'template' => 'https://tv.apple.com/show/%s',
|
||||||
|
'title' => 'Apple TV',
|
||||||
|
],
|
||||||
|
'P11460' => [
|
||||||
|
'template' => 'https://app.plex.tv/desktop/#!/provider/tv.plex.provider.metadata/details?key=/library/metadata/%s',
|
||||||
|
'title' => 'Plex',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
];
|
|
@ -1,49 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
use Illuminate\Database\Migrations\Migration;
|
|
||||||
use Illuminate\Database\Schema\Blueprint;
|
|
||||||
use Illuminate\Support\Facades\Schema;
|
|
||||||
|
|
||||||
return new class extends Migration
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Run the migrations.
|
|
||||||
*/
|
|
||||||
public function up(): void
|
|
||||||
{
|
|
||||||
Schema::create('users', function (Blueprint $table) {
|
|
||||||
$table->id();
|
|
||||||
$table->string('name');
|
|
||||||
$table->string('email')->unique();
|
|
||||||
$table->timestamp('email_verified_at')->nullable();
|
|
||||||
$table->string('password');
|
|
||||||
$table->rememberToken();
|
|
||||||
$table->timestamps();
|
|
||||||
});
|
|
||||||
|
|
||||||
Schema::create('password_reset_tokens', function (Blueprint $table) {
|
|
||||||
$table->string('email')->primary();
|
|
||||||
$table->string('token');
|
|
||||||
$table->timestamp('created_at')->nullable();
|
|
||||||
});
|
|
||||||
|
|
||||||
Schema::create('sessions', function (Blueprint $table) {
|
|
||||||
$table->string('id')->primary();
|
|
||||||
$table->foreignId('user_id')->nullable()->index();
|
|
||||||
$table->string('ip_address', 45)->nullable();
|
|
||||||
$table->text('user_agent')->nullable();
|
|
||||||
$table->longText('payload');
|
|
||||||
$table->integer('last_activity')->index();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reverse the migrations.
|
|
||||||
*/
|
|
||||||
public function down(): void
|
|
||||||
{
|
|
||||||
Schema::dropIfExists('users');
|
|
||||||
Schema::dropIfExists('password_reset_tokens');
|
|
||||||
Schema::dropIfExists('sessions');
|
|
||||||
}
|
|
||||||
};
|
|
|
@ -1,35 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
use Illuminate\Database\Migrations\Migration;
|
|
||||||
use Illuminate\Database\Schema\Blueprint;
|
|
||||||
use Illuminate\Support\Facades\Schema;
|
|
||||||
|
|
||||||
return new class extends Migration
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Run the migrations.
|
|
||||||
*/
|
|
||||||
public function up(): void
|
|
||||||
{
|
|
||||||
Schema::create('cache', function (Blueprint $table) {
|
|
||||||
$table->string('key')->primary();
|
|
||||||
$table->mediumText('value');
|
|
||||||
$table->integer('expiration');
|
|
||||||
});
|
|
||||||
|
|
||||||
Schema::create('cache_locks', function (Blueprint $table) {
|
|
||||||
$table->string('key')->primary();
|
|
||||||
$table->string('owner');
|
|
||||||
$table->integer('expiration');
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reverse the migrations.
|
|
||||||
*/
|
|
||||||
public function down(): void
|
|
||||||
{
|
|
||||||
Schema::dropIfExists('cache');
|
|
||||||
Schema::dropIfExists('cache_locks');
|
|
||||||
}
|
|
||||||
};
|
|
|
@ -1,57 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
use Illuminate\Database\Migrations\Migration;
|
|
||||||
use Illuminate\Database\Schema\Blueprint;
|
|
||||||
use Illuminate\Support\Facades\Schema;
|
|
||||||
|
|
||||||
return new class extends Migration
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Run the migrations.
|
|
||||||
*/
|
|
||||||
public function up(): void
|
|
||||||
{
|
|
||||||
Schema::create('jobs', function (Blueprint $table) {
|
|
||||||
$table->id();
|
|
||||||
$table->string('queue')->index();
|
|
||||||
$table->longText('payload');
|
|
||||||
$table->unsignedTinyInteger('attempts');
|
|
||||||
$table->unsignedInteger('reserved_at')->nullable();
|
|
||||||
$table->unsignedInteger('available_at');
|
|
||||||
$table->unsignedInteger('created_at');
|
|
||||||
});
|
|
||||||
|
|
||||||
Schema::create('job_batches', function (Blueprint $table) {
|
|
||||||
$table->string('id')->primary();
|
|
||||||
$table->string('name');
|
|
||||||
$table->integer('total_jobs');
|
|
||||||
$table->integer('pending_jobs');
|
|
||||||
$table->integer('failed_jobs');
|
|
||||||
$table->longText('failed_job_ids');
|
|
||||||
$table->mediumText('options')->nullable();
|
|
||||||
$table->integer('cancelled_at')->nullable();
|
|
||||||
$table->integer('created_at');
|
|
||||||
$table->integer('finished_at')->nullable();
|
|
||||||
});
|
|
||||||
|
|
||||||
Schema::create('failed_jobs', function (Blueprint $table) {
|
|
||||||
$table->id();
|
|
||||||
$table->string('uuid')->unique();
|
|
||||||
$table->text('connection');
|
|
||||||
$table->text('queue');
|
|
||||||
$table->longText('payload');
|
|
||||||
$table->longText('exception');
|
|
||||||
$table->timestamp('failed_at')->useCurrent();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reverse the migrations.
|
|
||||||
*/
|
|
||||||
public function down(): void
|
|
||||||
{
|
|
||||||
Schema::dropIfExists('jobs');
|
|
||||||
Schema::dropIfExists('job_batches');
|
|
||||||
Schema::dropIfExists('failed_jobs');
|
|
||||||
}
|
|
||||||
};
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::create('wikidata_properties', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
$table->string('property_id')->unique();
|
||||||
|
$table->string('property_type')->nullable();
|
||||||
|
$table->text('label')->nullable();
|
||||||
|
$table->text('description')->nullable();
|
||||||
|
$table->text('alt_label')->nullable();
|
||||||
|
$table->timestamps();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('wikidata_properties');
|
||||||
|
}
|
||||||
|
};
|
Loading…
Reference in New Issue
Block a user