Skip to content

Commit

Permalink
✨ import new stations from Wikidata (#2843)
Browse files Browse the repository at this point in the history
  • Loading branch information
MrKrisKrisu authored Aug 11, 2024
1 parent ecce034 commit fec72b0
Show file tree
Hide file tree
Showing 7 changed files with 115 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
use Illuminate\Database\Eloquent\ModelNotFoundException;
use JsonException;

readonly class WikidataObject
readonly class WikidataEntity
{

public string $qId;
Expand Down
24 changes: 24 additions & 0 deletions app/Http/Controllers/Frontend/Admin/StationController.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@
use App\Models\Station;
use App\Models\StationName;
use App\Objects\LineSegment;
use App\Services\Wikidata\WikidataImportService;
use App\Services\Wikidata\WikidataQueryService;
use Illuminate\Auth\Access\AuthorizationException;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
use Illuminate\View\View;
Expand Down Expand Up @@ -116,4 +119,25 @@ public function fetchWikidata(int $id): void {
]);
}
}

/**
* @param Request $request
*
* @return RedirectResponse
* @throws AuthorizationException
* @todo Make this an API endpoint when it is accessible for users too
*/
public function importWikidata(Request $request): RedirectResponse {
$this->authorize('create', Station::class);
$validated = $request->validate([
'qId' => ['required', 'string', 'regex:/^Q\d+$/'],
]);
try {
$station = WikidataImportService::importStation($validated['qId']);
return redirect()->route('admin.station', ['id' => $station->id])->with('alert-success', 'Station imported successfully');
} catch (\Exception $exception) {
Log::error('Error while importing wikidata station (manually): ' . $exception->getMessage());
return redirect()->back()->with('alert-danger', 'Error while importing station: ' . $exception->getMessage());
}
}
}
58 changes: 58 additions & 0 deletions app/Services/Wikidata/WikidataImportService.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<?php declare(strict_types=1);

namespace App\Services\Wikidata;

use App\Dto\Wikidata\WikidataEntity;
use App\Models\Station;

class WikidataImportService
{

public static function importStation(string $qId): Station {
$wikidataEntity = WikidataEntity::fetch($qId);

$name = $wikidataEntity->getClaims('P1448')[0]['mainsnak']['datavalue']['value']['text'] //P1448 = official name
?? $wikidataEntity->getLabel('de') //german label
?? $wikidataEntity->getLabel(); //english label or null if also not available

if ($name === null) {
throw new \InvalidArgumentException('No name found for entity ' . $qId);
}

$coordinates = $wikidataEntity->getClaims('P625')[0]['mainsnak']['datavalue']['value'] ?? null; //P625 = coordinate location
if ($coordinates === null) {
throw new \InvalidArgumentException('No coordinates found for entity ' . $qId);
}

$latitude = $coordinates['latitude'];
$longitude = $coordinates['longitude'];
$ibnr = $wikidataEntity->getClaims('P954')[0]['mainsnak']['datavalue']['value'] ?? null; //P954 = IBNR
$rl100 = $wikidataEntity->getClaims('P8671')[0]['mainsnak']['datavalue']['value'] ?? null; //P8671 = RL100
$ifopt = $wikidataEntity->getClaims('P12393')[0]['mainsnak']['datavalue']['value'] ?? null; //P12393 = IFOPT
if ($ifopt !== null) {
$splittedIfopt = explode(':', $ifopt);
}

//if ibnr is already in use, we can't import the station
if ($ibnr !== null && Station::where('ibnr', $ibnr)->exists()) {
throw new \InvalidArgumentException('IBNR ' . $ibnr . ' already in use');
}

return Station::create(
[
'name' => $name,
'latitude' => $latitude,
'longitude' => $longitude,
'wikidata_id' => $qId,
'rilIdentifier' => $rl100,
'ibnr' => $ibnr,
'ifopt_a' => $splittedIfopt[0] ?? null,
'ifopt_b' => $splittedIfopt[1] ?? null,
'ifopt_c' => $splittedIfopt[2] ?? null,
'ifopt_d' => $splittedIfopt[3] ?? null,
'ifopt_e' => $splittedIfopt[4] ?? null,
]
);
}

}
4 changes: 2 additions & 2 deletions app/Services/Wikidata/WikidataQueryService.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

namespace App\Services\Wikidata;

use App\Dto\Wikidata\WikidataObject;
use App\Dto\Wikidata\WikidataEntity;
use EasyRdf\Sparql\Client;

class WikidataQueryService
Expand Down Expand Up @@ -39,7 +39,7 @@ private function parseObjects(): void {
foreach ($this->results as $result) {
$uri = $result->item->getUri();
$qId = substr($uri, strrpos($uri, '/') + 1);
$this->objects[] = WikidataObject::fetch($qId);
$this->objects[] = WikidataEntity::fetch($qId);
}
}
}
17 changes: 17 additions & 0 deletions resources/views/admin/stations/list.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,23 @@ function deleteStation(id) {
</script>
</div>
</div>
<div class="card mb-3">
<div class="card-body">
<h2 class="fs-5">Import from Wikidata</h2>
<form method="POST" action="{{route('backend.status.import.wikidata')}}">
@csrf
<div class="form-floating">
<input type="text" class="form-control" id="input-import-wikidata-entity" required
name="qId">
<label for="input-import-wikidata-entity" class="form-label">Wikidata ID</label>
</div>
<br/>
<button type="submit" class="btn btn-primary">Import</button>
</form>
</div>
</div>
</div>
</div>
Expand Down
21 changes: 12 additions & 9 deletions resources/views/admin/trip/show.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -121,12 +121,11 @@
<tr>
<th scope="col">Name</th>
<th scope="col">TRWL-ID</th>
<th scope="col">Wikidata</th>
<th scope="col">IBNR</th>
<th scope="col">RIL100</th>
<th scope="col">Ankunft plan</th>
<th scope="col">real</th>
<th scope="col">Abfahrt plan</th>
<th scope="col">real</th>
<th scope="col">RL100</th>
<th scope="col">Ankunft soll / ist</th>
<th scope="col">Abfahrt soll / ist</th>
</tr>
</thead>
<tbody>
Expand All @@ -138,18 +137,22 @@
</a>
</td>
<td>{{$stopover->station?->id}}</td>
<td>
<a href="https://www.wikidata.org/wiki/{{$stopover->station?->wikidata_id}}"
target="__blank">
{{$stopover->station?->wikidata_id}}
</a>
</td>
<td>{{$stopover->station?->ibnr}}</td>
<td>{{$stopover->station?->rilIdentifier}}</td>
<td title="{{$stopover->arrival_planned?->format('c')}}">
{{userTime($stopover->arrival_planned)}}
</td>
<td title="{{$stopover->arrival_real?->format('c')}}">
/
{{userTime($stopover->arrival_real?->format('H:i'))}}
</td>
<td title="{{$stopover->departure_planned?->format('c')}}">
{{userTime($stopover->departure_planned)}}
</td>
<td title="{{$stopover->departure_real?->format('c')}}">
/
{{userTime($stopover->departure_real)}}
</td>
</tr>
Expand Down
1 change: 1 addition & 0 deletions routes/web/admin.php
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@
Route::get('/{id}', [StationController::class, 'renderStation'])
->name('admin.station');

Route::post('/wikidata/import', [StationController::class, 'importWikidata'])->name('backend.status.import.wikidata'); //TODO: Make this an API endpoint when it is accessible for users too
Route::post('/{id}/wikidata', [StationController::class, 'fetchWikidata']);
});

Expand Down

0 comments on commit fec72b0

Please sign in to comment.