add schedule updating

This commit is contained in:
Kacper Donat 2019-01-12 23:10:13 +01:00
parent ca8b360936
commit 5a9096830f
9 changed files with 262 additions and 30 deletions

View File

@ -5,6 +5,8 @@ doctrine:
dbal:
driver: 'pdo_sqlite'
url: '%env(resolve:DATABASE_URL)%'
logging: false
profiling: false
orm:
auto_generate_proxy_classes: '%kernel.debug%'

View File

@ -49,9 +49,9 @@ class TripEntity implements Entity, Fillable
private $note;
/**
* @var Collection<StopInTrack>
* @var Collection<TripStopEntity>
*
* @ORM\OneToMany(targetEntity=StopInTrack::class, fetch="EXTRA_LAZY", mappedBy="track", cascade={"persist"})
* @ORM\OneToMany(targetEntity=TripStopEntity::class, fetch="EXTRA_LAZY", mappedBy="trip", cascade={"persist"})
* @ORM\OrderBy({"order": "ASC"})
*/
private $stops;

View File

@ -11,7 +11,7 @@ use Doctrine\ORM\Mapping as ORM;
* @ORM\Entity
* @ORM\Table("trip_stop")
*/
class TripStop implements Fillable
class TripStopEntity implements Fillable
{
use FillTrait;
@ -32,6 +32,7 @@ class TripStop implements Fillable
* @var int
*
* @ORM\Column(name="sequence", type="integer")
* @ORM\Id
*/
private $order;

View File

@ -15,7 +15,7 @@ final class Version20190111212909 extends AbstractMigration
// this up() migration is auto-generated, please modify it to your needs
$this->abortIf($this->connection->getDatabasePlatform()->getName() !== 'sqlite', 'Migration can only be executed safely on \'sqlite\'.');
$this->addSql('CREATE TABLE trip_stop (stop_id VARCHAR(255) NOT NULL, trip_id VARCHAR(255) NOT NULL, sequence INTEGER NOT NULL, arrival DATETIME NOT NULL, departure DATETIME NOT NULL, PRIMARY KEY(stop_id, trip_id))');
$this->addSql('CREATE TABLE trip_stop (stop_id VARCHAR(255) NOT NULL, trip_id VARCHAR(255) NOT NULL, sequence INTEGER NOT NULL, arrival DATETIME NOT NULL, departure DATETIME NOT NULL, PRIMARY KEY(stop_id, trip_id, sequence))');
$this->addSql('CREATE INDEX IDX_926E85DD3902063D ON trip_stop (stop_id)');
$this->addSql('CREATE INDEX IDX_926E85DDA5BC2E0E ON trip_stop (trip_id)');
$this->addSql('CREATE TABLE trip (id VARCHAR(255) NOT NULL, operator_id VARCHAR(255) DEFAULT NULL, track_id VARCHAR(255) DEFAULT NULL, provider_id VARCHAR(255) DEFAULT NULL, variant VARCHAR(255) DEFAULT NULL, note VARCHAR(255) DEFAULT NULL, PRIMARY KEY(id))');

View File

@ -0,0 +1,74 @@
<?php
namespace App\Model;
use Carbon\Carbon;
class ScheduleStop implements Fillable
{
use FillTrait;
/**
* Stop (as a place) related to that scheduled bus stop
* @var Stop
*/
private $stop;
/**
* Order in trip
* @var int
*/
private $order;
/**
* Arrival time
* @var Carbon
*/
private $arrival;
/**
* Departure time
* @var Carbon
*/
private $departure;
public function getStop()
{
return $this->stop;
}
public function setStop($stop): void
{
$this->stop = $stop;
}
public function getOrder(): int
{
return $this->order;
}
public function setOrder(int $order): void
{
$this->order = $order;
}
public function getArrival(): Carbon
{
return $this->arrival;
}
public function setArrival(Carbon $arrival): void
{
$this->arrival = $arrival;
}
public function getDeparture(): Carbon
{
return $this->departure;
}
public function setDeparture(Carbon $departure): void
{
$this->departure = $departure;
}
}

83
src/Model/Trip.php Normal file
View File

@ -0,0 +1,83 @@
<?php
namespace App\Model;
use Tightenco\Collect\Support\Collection;
class Trip implements Referable, Fillable
{
use ReferableTrait, FillTrait;
/**
* Line variant describing trip, for example 'a'
* @var string|null
*
*/
private $variant;
/**
* Trip description
* @var string|null
*/
private $description;
/**
* Line reference
* @var ?Track
*/
private $track;
/**
* Stops in track
* @var Collection<ScheduleStop>
*/
private $schedule;
/**
* Track constructor.
*/
public function __construct()
{
$this->setSchedule([]);
}
public function getVariant(): ?string
{
return $this->variant;
}
public function setVariant(?string $variant): void
{
$this->variant = $variant;
}
public function getDescription(): ?string
{
return $this->description;
}
public function setDescription(?string $description): void
{
$this->description = $description;
}
public function getTrack(): ?Track
{
return $this->track;
}
public function setTrack(?Track $track): void
{
$this->track = $track;
}
public function getSchedule(): Collection
{
return $this->schedule;
}
public function setSchedule($schedule = [])
{
return $this->schedule = collect($schedule);
}
}

View File

@ -8,13 +8,17 @@ use App\Entity\ProviderEntity;
use App\Entity\StopEntity;
use App\Entity\StopInTrack;
use App\Entity\TrackEntity;
use App\Entity\TripEntity;
use App\Entity\TripStopEntity;
use App\Model\Line as LineModel;
use App\Provider\ZtmGdansk\ZtmGdanskProvider;
use App\Service\DataUpdater;
use App\Service\IdUtils;
use Carbon\Carbon;
use Doctrine\ORM\EntityManagerInterface;
use function Kadet\Functional\partial;
use Psr\Log\LoggerInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Tightenco\Collect\Support\Collection;
class ZtmGdanskDataUpdateSubscriber implements EventSubscriberInterface
{
@ -62,11 +66,9 @@ class ZtmGdanskDataUpdateSubscriber implements EventSubscriberInterface
$save = [$this->em, 'persist'];
$this->getOperators($provider)->each($save);
$this->getLines($provider)->each($save);
$this->getStops($provider)->each($save);
$this->getTracks($provider)->each($save);
$this->em->flush();
$this->getLines($provider)->each($save)->each(partial([$this, 'getSchedule'], $provider, $save));
}
private function getOperators(ProviderEntity $provider)
@ -190,6 +192,66 @@ class ZtmGdanskDataUpdateSubscriber implements EventSubscriberInterface
});
}
public function getSchedule(ProviderEntity $provider, callable $save, LineEntity $line)
{
$this->logger->info(sprintf('Obtaining schedule for line %s from ZTM Gdańsk', $line->getId()));
$schedule = file_get_contents("http://87.98.237.99:88/stopTimes?date=".(date('Y-m-d'))."&routeId=".$this->ids->of($line));
$schedule = json_decode($schedule, true)['stopTimes'];
$schedule = collect($schedule)->groupBy(function ($stop) {
return sprintf("%s-%d", $stop['busServiceName'], $stop['order']);
});
collect($schedule)->map(function (Collection $trips, $id) use ($provider) {
$entity = TripEntity::createFromArray([
'id' => $this->ids->generate($provider, $id),
'operator' => $this->em->getReference(
OperatorEntity::class,
$this->ids->generate($provider, $trips->first()['agencyId'])
),
'track' => $this->em->getReference(
TrackEntity::class,
$this->ids->generate($provider, $trips->first()['tripId'])
),
'variant' => $trips->first(function ($trip) {
return !empty($trip['noteSymbol']);
}, ['noteSymbol' => null])['noteSymbol'],
'note' => $trips->first(function ($trip) {
return !empty($trip['noteSymbol']);
}, ['noteDescription' => null])['noteDescription'],
]);
$stops = $trips->map(function ($stop) use ($entity, $provider) {
$base = Carbon::create(1899, 12, 30, 00, 00, 00);
$date = Carbon::createFromFormat('Y-m-d', $stop['date'])->setTime(00, 00, 00);
$arrival = $base->diff(Carbon::createFromTimeString($stop['arrivalTime']));
$departure = $base->diff(Carbon::createFromTimeString($stop['departureTime']));
$arrival = (clone $date)->add($arrival);
$departure = (clone $date)->add($departure);
return TripStopEntity::createFromArray([
'trip' => $entity,
'stop' => $this->em->getReference(
StopEntity::class,
$this->ids->generate($provider, $stop['stopId'])
),
'order' => $stop['stopSequence'],
'arrival' => $arrival,
'departure' => $departure,
]);
});
$entity->setStops($stops);
return $entity;
})->each($save);
$this->em->flush();
$this->em->clear();
}
public static function getSubscribedEvents()
{
return [

View File

@ -31,20 +31,13 @@ class DataUpdater
public function update()
{
$connection = $this->em->getConnection();
$connection->getConfiguration()->setSQLLogger(null);
$schema = $connection->getSchemaManager();
try {
$connection->beginTransaction();
collect($schema->listTables())->reject(function (Table $schema) {
return $schema->getName() === 'migration_versions';
})->each([$schema, 'dropAndCreateTable']);
collect($schema->listTables())->reject(function (Table $schema) {
return $schema->getName() === 'migration_versions';
})->each([$schema, 'dropAndCreateTable']);
$this->dispatcher->dispatch(self::UPDATE_EVENT, new DataUpdateEvent());
$connection->commit();
} catch (\Throwable $exception) {
$connection->rollBack();
throw $exception;
}
$this->dispatcher->dispatch(self::UPDATE_EVENT, new DataUpdateEvent());
}
}

View File

@ -2,15 +2,8 @@
namespace App\Service;
use App\Entity\Entity;
use App\Entity\LineEntity;
use App\Entity\OperatorEntity;
use App\Entity\StopEntity;
use App\Entity\TrackEntity;
use App\Model\Line;
use App\Model\Operator;
use App\Model\Stop;
use App\Model\Track;
use App\Entity\{Entity, LineEntity, OperatorEntity, StopEntity, TrackEntity, TripEntity, TripStopEntity};
use App\Model\{Line, Operator, ScheduleStop, Stop, Track, Trip};
use App\Service\Proxy\ReferenceFactory;
use Doctrine\ORM\PersistentCollection;
use Doctrine\ORM\Proxy\Proxy;
@ -33,7 +26,7 @@ final class EntityConverter
* @param Entity $entity
* @param array $cache
*
* @return Line|Track|Stop|Operator
* @return Line|Track|Stop|Operator|Trip|ScheduleStop
*/
public function convert(Entity $entity, array $cache = [])
{
@ -93,6 +86,24 @@ final class EntityConverter
],
]);
break;
case $entity instanceof TripEntity:
$result->fill([
'variant' => $entity->getVariant(),
'note' => $entity->getNote(),
'schedule' => $this->collection($entity->getStops())->map($convert),
'track' => $convert($entity->getTrack()),
]);
break;
case $entity instanceof TripStopEntity:
$result->fill([
'arrival' => $entity->getArrival(),
'departure' => $entity->getDeparture(),
'stop' => $convert($entity->getStop()),
'order' => $convert($entity->getOrder()),
]);
break;
}
return $result;
@ -134,6 +145,12 @@ final class EntityConverter
case $entity instanceof StopEntity:
return Stop::class;
case $entity instanceof TripEntity:
return Trip::class;
case $entity instanceof TripStopEntity:
return ScheduleStop::class;
default:
return false;
}