Covivo/mobicoop

View on GitHub
api/src/RdexPlus/Resource/Journey.php

Summary

Maintainability
B
6 hrs
Test Coverage
<?php

/**
 * Copyright (c) 2021, MOBICOOP. All rights reserved.
 * This project is dual licensed under AGPL and proprietary licence.
 ***************************
 *    This program is free software: you can redistribute it and/or modify
 *    it under the terms of the GNU Affero General Public License as
 *    published by the Free Software Foundation, either version 3 of the
 *    License, or (at your option) any later version.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU Affero General Public License for more details.
 *
 *    You should have received a copy of the GNU Affero General Public License
 *    along with this program.  If not, see <gnu.org/licenses>.
 ***************************
 *    Licence MOBICOOP described in the file
 *    LICENSE
 **************************/

namespace App\RdexPlus\Resource;

use ApiPlatform\Core\Annotation\ApiResource;
use ApiPlatform\Core\Annotation\ApiProperty;
use App\RdexPlus\Entity\Geopoint;
use App\RdexPlus\Entity\Price;
use App\RdexPlus\Entity\User;
use App\RdexPlus\Entity\Waypoint;
use App\RdexPlus\Entity\WaySchedule;
use Symfony\Component\Serializer\Annotation\Groups;
use Symfony\Component\Validator\Constraints as Assert;

/**
 * RDEX+ : Journey
 * Documentation : https://rdex.fabmob.io/
 * Exemple of a regular round trip
 *{
 *   "type":"planned",
 *   "user":{
 *       "id":"18"
 *   },
 *  "isRoundTrip":true,
 *  "frequency":"regular",
 *  "price":{
 *      "amount":0.06,
 *      "type":"variable"
 *  },
 *  "carpoolerType":"driver",
 *  "from":{
 *    "latitude": 48.690303,
 *    "longitude": 6.178289,
 *    "city": "Nancy"
 *  },
 *  "to":{
 *    "latitude": 49.115164,
 *    "longitude": 6.17963,
 *    "city": "Metz"
 *  },
 *  "numberOfWaypoints":1,
 *  "waypoints":[
 *    {
 *        "latitude": 48.7658301,
 *        "longitude": 6.1229922,
 *        "city": "Pompey"
 *    },
 *    {
 *        "latitude": 48.9025946,
 *        "longitude": 6.0547691,
 *        "city": "Pont-à-Mousson"
 *    }
 *   ],
 *  "outward":{
 *    "departureDate":1622448000,
 *    "regularSchedule":[
 *        {
 *            "mondayTime":"08:00",
 *            "wednesdayTime":"08:00"
 *        },
 *        {
 *            "fridayTime":"09:00"
 *        }
 *    ]
 *  },
 *  "return":{
 *    "departureDate":1622484000,
 *    "regularSchedule":[
 *        {
 *            "mondayTime":"18:00",
 *            "wednesdayTime":"18:00"
 *        },
 *        {
 *            "fridayTime":"19:00"
 *        }
 *    ]
 *  }
 *}
 * The RDEX+ protocol does'nt require the POST route. We did it anyway.
 *
 * @ApiResource(
 *      routePrefix="/interoperability",
 *      attributes={
 *          "normalization_context"={"groups"={"rdexPlusRead"}, "enable_max_depth"="true"},
 *          "denormalization_context"={"groups"={"rdexPlusWrite"}}
 *      },
 *      collectionOperations={
 *          "rdex_plus_journey_get"={
 *              "method"="GET",
 *              "path"="/journeys",
 *              "security"="is_granted('ad_list',object)",
 *              "swagger_context" = {
 *                  "summary"="Search for matching journeys",
 *                  "tags"={"Interoperability", "RDEX+"}
 *              }
 *          },
 *          "rdex_plus_journey_post"={
 *              "method"="POST",
 *              "path"="/journeys",
 *              "security_post_denormalize"="is_granted('ad_search_create',object)",
 *              "swagger_context" = {
 *                  "summary"="Publish a journey",
 *                  "tags"={"Interoperability", "RDEX+"}
 *              }
 *          }
 *      },
 *      itemOperations={
 *          "rdex_plus_journey_get_item"={
 *              "method"="GET",
 *              "path"="/journeys/{id}",
 *              "security"="is_granted('reject',object)",
 *              "swagger_context" = {
 *                  "summary"="Get a journey (not implemented)",
 *                  "tags"={"Interoperability", "RDEX+"}
 *              }
 *          }
 *      }
 * )
 * @author Maxime Bardot <maxime.bardot@mobicoop.org>
 */
class Journey
{
    const DEFAULT_ID = "999999999999";

    const TYPE_PLANNED = "planned";
    const TYPE_DYNAMIC = "dynamic";
    const TYPE_LINE = "line";
    const VALID_TYPES = [
        self::TYPE_PLANNED,
        self::TYPE_DYNAMIC,
        self::TYPE_LINE
    ];

    const CARPOOLER_TYPE_DRIVER = "driver";
    const CARPOOLER_TYPE_PASSENGER = "passenger";
    const CARPOOLER_TYPE_BOTH = "both";
    const VALID_CARPOOLER_TYPES = [
        self::CARPOOLER_TYPE_DRIVER,
        self::CARPOOLER_TYPE_PASSENGER,
        self::CARPOOLER_TYPE_BOTH
    ];

    const FREQUENCY_PUNCTUAL = "punctual";
    const FREQUENCY_REGULAR = "regular";
    const FREQUENCY_BOTH = "both";
    const VALID_FREQUENCIES = [
        self::FREQUENCY_PUNCTUAL,
        self::FREQUENCY_REGULAR,
        self::FREQUENCY_BOTH
    ];

    const TIME_MARGIN_DEFAULT = 900;

    /**
     * @var string Journey's id
     *
     * @ApiProperty(identifier=true)
     * @Groups({"rdexPlusRead"})
     */
    private $id;

    /**
     * @var string Journey's direct URL
     *
     * @Groups({"rdexPlusRead"})
     */
    private $webUrl;

    /**
     * @var string Journey's type (planned, dynamic, line)
     * @Assert\NotBlank
     * @Groups({"rdexPlusRead","rdexPlusWrite"})
     */
    private $type;

    /**
     * @var string Journey's operator
     *
     * @Groups({"rdexPlusRead"})
     */
    private $operator;

    /**
     * @var string Journey's operator's website
     *
     * @Groups({"rdexPlusRead"})
     */
    private $operatorUrl;
    
    /**
     * @var string Journey's carpooler's type (driver, passenger, both)
     * On GET : it's the role the poster is looking for
     * On POST : it's the role of the poster
     * @Assert\NotBlank
     *
     * @Groups({"rdexPlusRead","rdexPlusWrite"})
     */
    private $carpoolerType;

    /**
     * @var User Journey's carpooler
     * @Assert\NotBlank
     * @Groups({"rdexPlusRead","rdexPlusWrite"})
     */
    private $user;

    /**
     * @var int Journey's available seats (required if carpoolerType = driver or both)
     *
     * @Groups({"rdexPlusRead","rdexPlusWrite"})
     */
    private $availableSeats;

    /**
     * @var int Journey's available seats (required if carpoolerType = passenger)
     *
     * @Groups({"rdexPlusRead","rdexPlusWrite"})
     */
    private $requestedSeats;

    /**
     * @var Geopoint Journey's origin
     * @Assert\NotBlank
     *
     * @Groups({"rdexPlusRead","rdexPlusWrite"})
     */
    private $from;
    
    /**
     * @var Geopoint Journey's destination
     * @Assert\NotBlank
     *
     * @Groups({"rdexPlusRead","rdexPlusWrite"})
     */
    private $to;

    /**
     * @var int Journey's duration in seconds
     *
     * @Groups({"rdexPlusRead"})
     */
    private $duration;

    /**
     * @var int Journey's duration in seconds
     *
     * @Groups({"rdexPlusRead"})
     */
    private $distance;

    /**
     * @var int Journey's nomber of waypoints
     *
     * @Groups({"rdexPlusRead","rdexPlusWrite"})
     */
    private $numberOfWaypoints;
    
    /**
     * @var Waypoint[] Journey's waypoints (required if numberOfWaypoints>0)
     *
     * @Groups({"rdexPlusRead","rdexPlusWrite"})
     */
    private $waypoints;

    /**
     * @var Price Journey's price
     * @Assert\NotBlank
     *
     * @Groups({"rdexPlusRead","rdexPlusWrite"})
     */
    private $price;

    /**
     * @var string Journey's free comment
     *
     * @Groups({"rdexPlusRead","rdexPlusWrite"})
     */
    private $details;

    /**
     * @var string Journey's frequency (punctual, regular, both)
     * both : only on GET
     * @Assert\NotBlank
     * @Groups({"rdexPlusRead","rdexPlusWrite"})
     */
    private $frequency;

    /**
     * @var bool If the journey is a round trip
     * @Assert\Type("bool")
     * @Assert\NotNull
     * @Groups({"rdexPlusRead","rdexPlusWrite"})
     */
    private $isRoundTrip;

    /**
     * @var bool If the journey is now stopped
     *
     * @Groups({"rdexPlusRead","rdexPlusWrite"})
     */
    private $isStopped;

    /**
     * @var WaySchedule Outward date, time and regular informations
     *
     * @Groups({"rdexPlusRead","rdexPlusWrite"})
     */
    private $outward;

    /**
     * @var WaySchedule Return date, time and regular informations (required if isRoundTrip = true)
     *
     * @Groups({"rdexPlusRead","rdexPlusWrite"})
     */
    private $return;
    
    public function __construct(int $id = null)
    {
        if (is_null($id)) {
            $this->id = self::DEFAULT_ID;
        } else {
            $this->id = $id;
        }
    }

    public function getId(): ?string
    {
        return $this->id;
    }

    public function setId(?string $id): self
    {
        $this->id = $id;

        return $this;
    }

    public function getWebUrl(): ?string
    {
        return $this->webUrl;
    }

    public function setWebUrl(?string $webUrl): self
    {
        $this->webUrl = $webUrl;

        return $this;
    }

    public function getType(): ?string
    {
        return $this->type;
    }

    public function setType(?string $type): self
    {
        $this->type = $type;

        return $this;
    }

    public function getOperator(): ?string
    {
        return $this->operator;
    }

    public function setOperator(?string $operator): self
    {
        $this->operator = $operator;

        return $this;
    }

    public function getOperatorUrl(): ?string
    {
        return $this->operatorUrl;
    }

    public function setOperatorUrl(?string $operatorUrl): self
    {
        $this->operatorUrl = $operatorUrl;

        return $this;
    }

    public function getCarpoolerType(): ?string
    {
        return $this->carpoolerType;
    }

    public function setCarpoolerType(?string $carpoolerType): self
    {
        $this->carpoolerType = $carpoolerType;

        return $this;
    }

    public function getUser(): ?User
    {
        return $this->user;
    }

    public function setUser(?User $user): self
    {
        $this->user = $user;

        return $this;
    }

    public function getAvailableSeats(): ?int
    {
        return $this->availableSeats;
    }

    public function setAvailableSeats(?int $availableSeats): self
    {
        $this->availableSeats = $availableSeats;

        return $this;
    }
    
    public function getRequestedSeats(): ?int
    {
        return $this->requestedSeats;
    }

    public function setRequestedSeats(?int $requestedSeats): self
    {
        $this->requestedSeats = $requestedSeats;

        return $this;
    }

    public function getFrom(): ?Geopoint
    {
        return $this->from;
    }

    public function setFrom(?Geopoint $from): self
    {
        $this->from = $from;

        return $this;
    }
    
    public function getTo(): ?Geopoint
    {
        return $this->to;
    }

    public function setTo(?Geopoint $to): self
    {
        $this->to = $to;

        return $this;
    }

    public function getDuration(): ?int
    {
        return $this->duration;
    }

    public function setDuration(?int $duration): self
    {
        $this->duration = $duration;

        return $this;
    }
    
    public function getDistance(): ?int
    {
        return $this->distance;
    }

    public function setistance(?int $distance): self
    {
        $this->distance = $distance;

        return $this;
    }
    
    public function getNumberOfWaypoints(): ?int
    {
        return $this->numberOfWaypoints;
    }

    public function setNumberOfWaypoints(?int $numberOfWaypoints): self
    {
        $this->numberOfWaypoints = $numberOfWaypoints;

        return $this;
    }
    
    public function getWaypoints(): ?array
    {
        return $this->waypoints;
    }

    public function setWaypoints(?array $waypoints): self
    {
        $this->waypoints = $waypoints;

        return $this;
    }
    
    public function getPrice(): ?Price
    {
        return $this->price;
    }

    public function setPrice(?Price $price): self
    {
        $this->price = $price;

        return $this;
    }

    public function getDetails(): ?string
    {
        return $this->details;
    }

    public function setDetails(?string $details): self
    {
        $this->details = $details;

        return $this;
    }

    public function getFrequency(): ?string
    {
        return $this->frequency;
    }

    public function setFrequency(?string $frequency): self
    {
        $this->frequency = $frequency;

        return $this;
    }

    public function getIsRoundTrip(): ?bool
    {
        return $this->isRoundTrip;
    }

    public function setIsRoundTrip(?bool $isRoundTrip): self
    {
        $this->isRoundTrip = $isRoundTrip;

        return $this;
    }

    public function getIsStopped(): ?bool
    {
        return $this->isStopped;
    }

    public function setIsStopped(?bool $isStopped): self
    {
        $this->isStopped = $isStopped;

        return $this;
    }

    public function getOutward(): ?WaySchedule
    {
        return $this->outward;
    }

    public function setOutward(?WaySchedule $outward): self
    {
        $this->outward = $outward;

        return $this;
    }
    
    public function getReturn(): ?WaySchedule
    {
        return $this->return;
    }

    public function setReturn(?WaySchedule $return): self
    {
        $this->return = $return;

        return $this;
    }
}