src/Entity/Saloon/Saloon.php line 42

Open in your IDE?
  1. <?php
  2. /**
  3.  * Created by simpson <simpsonwork@gmail.com>
  4.  * Date: 2019-04-15
  5.  * Time: 19:50
  6.  */
  7. namespace App\Entity\Saloon;
  8. use AngelGamez\TranslatableBundle\Entity\TranslatableValue;
  9. use App\Entity\Account\Advertiser;
  10. use App\Entity\ApartmentsPricing;
  11. use App\Entity\Account\Customer;
  12. use App\Entity\ExpressPricing;
  13. use App\Entity\IProvidedService;
  14. use App\Entity\IProvidesServices;
  15. use App\Entity\Location\City;
  16. use App\Entity\Location\Station;
  17. use App\Entity\Location\MapCoordinate;
  18. use App\Entity\Messengers;
  19. use App\Entity\PhoneCallRestrictions;
  20. use App\Entity\Profile\Profile;
  21. use App\Entity\Sales\Saloon\AdBoardPlacement;
  22. use App\Entity\Saloon\Comment\CommentByCustomer;
  23. use App\Entity\Service;
  24. use App\Entity\Sales\Saloon\PlacementHiding;
  25. use App\Entity\ProvidedServiceTrait;
  26. use App\Entity\TakeOutPricing;
  27. use App\Helper\TopCardTrait;
  28. use App\Repository\SaloonRepository;
  29. use Carbon\Carbon;
  30. use Carbon\CarbonImmutable;
  31. use Doctrine\Common\Collections\ArrayCollection;
  32. use Doctrine\Common\Collections\Collection;
  33. use Doctrine\ORM\Mapping as ORM;
  34. use Gedmo\Mapping\Annotation as Gedmo;
  35. use Gedmo\SoftDeleteable\Traits\SoftDeleteableEntity;
  36. #[Gedmo\SoftDeleteable(fieldName"deletedAt"timeAwaretrue)]
  37. #[ORM\Table(name'saloons')]
  38. #[ORM\Entity(repositoryClassSaloonRepository::class)]
  39. class Saloon implements IProvidesServices
  40. {
  41.     use SoftDeleteableEntity;
  42.     use ProvidedServiceTrait;
  43.     use TopCardTrait;
  44.     #[ORM\Id]
  45.     #[ORM\Column(name'id'type'integer')]
  46.     #[ORM\GeneratedValue(strategy'AUTO')]
  47.     protected int $id;
  48.     #[ORM\JoinColumn(name'user_id'referencedColumnName'id'nullabletrue)]
  49.     #[ORM\ManyToOne(targetEntityAdvertiser::class, inversedBy'saloons')]
  50.     protected ?Advertiser $owner;
  51.     #[ORM\OneToOne(targetEntityAdBoardPlacement::class, mappedBy'saloon'cascade: ['all'])]
  52.     protected ?AdBoardPlacement $adBoardPlacement;
  53.     #[ORM\OneToOne(targetEntityPlacementHiding::class, mappedBy'saloon'cascade: ['all'])]
  54.     protected ?PlacementHiding $placementHiding;
  55.     #[ORM\Column(name'uri_identity'type'string'length128)]
  56.     protected string $uriIdentity;
  57.     #[ORM\Column(name'name'type'translatable')]
  58.     protected TranslatableValue $name;
  59.     #[ORM\Column(name'description'type'translatable')]
  60.     protected TranslatableValue $description;
  61.     /** @var SaloonService[] */
  62.     #[ORM\OneToMany(targetEntitySaloonService::class, mappedBy'saloon'cascade: ['all'], orphanRemovaltrue)]
  63.     #[ORM\Cache(usage'NONSTRICT_READ_WRITE')]
  64.     protected Collection $providedServices;
  65.     /** @var int[] */
  66.     #[ORM\Column(name'client_types'type'simple_array'nullabletrue)]
  67.     protected ?array $clientTypes;
  68.     /**
  69.      * Номера телефонов в свободной форме написания
  70.      */
  71.     #[ORM\Column(name'phone_number'type'string'length255)]
  72.     protected string $phoneNumber;
  73.     #[ORM\Embedded(class: Messengers::class, columnPrefixfalse)]
  74.     protected ?Messengers $messengers;
  75.     #[ORM\Embedded(class: PhoneCallRestrictions::class, columnPrefixfalse)]
  76.     protected ?PhoneCallRestrictions $phoneCallRestrictions;
  77.     #[ORM\Embedded(class: WorkingHours::class, columnPrefix'working_hours_')]
  78.     protected ?WorkingHours $workingHours;
  79.     /**
  80.      * Расценки в свободной форме написания
  81.      */
  82.     #[ORM\Column(name'prices'type'text'nullabletrue)]
  83.     protected ?string $prices;
  84.     #[ORM\Embedded(class: ApartmentsPricing::class, columnPrefixfalse)]
  85.     protected ?ApartmentsPricing $apartmentsPricing;
  86.     #[ORM\Embedded(class: TakeOutPricing::class, columnPrefixfalse)]
  87.     protected ?TakeOutPricing $takeOutPricing;
  88.     #[ORM\Embedded(class: ExpressPricing::class, columnPrefixfalse)]
  89.     protected ?ExpressPricing $expressPricing;
  90.     #[ORM\Column(name'extra_charge'type'integer'nullabletrue)]
  91.     protected ?int $extraCharge;
  92.     #[ORM\OneToOne(targetEntityThumbnail::class, mappedBy'saloon'cascade: ['all'], orphanRemovaltrue)]
  93.     protected ?Thumbnail $thumbnail null;
  94.     /** @var Photo[] */
  95.     #[ORM\OneToMany(targetEntityPhoto::class, mappedBy'saloon'cascade: ['all'], orphanRemovaltrue)]
  96.     protected Collection $photos;
  97.     /** @var Video[] */
  98.     #[ORM\OneToMany(targetEntityVideo::class, mappedBy'saloon'cascade: ['all'], orphanRemovaltrue)]
  99.     protected Collection $videos;
  100.     /** @var CommentByCustomer[] */
  101.     #[ORM\OneToMany(targetEntityCommentByCustomer::class, mappedBy'saloon')]
  102.     protected Collection $comments;
  103.     /** @var Profile[] */
  104.     #[ORM\OneToMany(targetEntityProfile::class, mappedBy'saloon')]
  105.     protected Collection $profiles;
  106.     #[ORM\JoinColumn(name'city_id'referencedColumnName'id')]
  107.     #[ORM\ManyToOne(targetEntityCity::class)]
  108.     protected City $city;
  109.     /** @var Station[] */
  110.     #[ORM\JoinTable(name'saloon_stations')]
  111.     #[ORM\JoinColumn(name'saloon_id'referencedColumnName'id')]
  112.     #[ORM\InverseJoinColumn(name'station_id'referencedColumnName'id')]
  113.     #[ORM\ManyToMany(targetEntityStation::class)]
  114.     protected Collection $stations;
  115.     /**
  116.      * Районы в свободной форме написания
  117.      */
  118.     #[ORM\Column(name'districts'type'string'length255nullabletrue)]
  119.     protected ?string $districts;
  120.     #[ORM\Column(name'address'type'translatable'nullabletrue)]
  121.     protected ?TranslatableValue $address;
  122.     #[ORM\Embedded(class: MapCoordinate::class, columnPrefixfalse)]
  123.     protected MapCoordinate $mapCoordinate;
  124.     #[ORM\Column(name'created_at'type'datetimetz_immutable'nullabletrue)]
  125.     protected ?\DateTimeImmutable $createdAt;
  126.     #[Gedmo\Timestampable(on"update")]
  127.     #[ORM\Column(name'updated_at'type'datetimetz_immutable'nullabletrue)]
  128.     protected ?\DateTimeImmutable $updatedAt;
  129.     #[ORM\Column(name'inactivated_at'type'datetimetz_immutable'nullabletrue)]
  130.     protected ?\DateTimeImmutable $inactivatedAt;
  131.     #[ORM\Column(name'email'type'string'length180nullabletrue)]
  132.     protected ?string $email null;
  133.     private bool $draft false;
  134.     #[ORM\Column(name'seo'type'json'nullabletrue)]
  135.     private ?array $seo null;
  136.     #[ORM\ManyToOne(targetEntityStation::class)]
  137.     #[ORM\JoinColumn(name'primary_station_id'referencedColumnName'id'nullabletrueonDelete'SET NULL')]
  138.     private ?Station $primaryStation null;
  139.     #[ORM\Column(type'smallint'options: ['default' => 0])]
  140.     private int $deleteMode 0;
  141.     public function __construct(string $uriIdentity, ?\DateTimeImmutable $createdAt null)
  142.     {
  143.         $this->draft true;
  144.         $this->uriIdentity $uriIdentity;
  145.         $this->createdAt $createdAt ?? CarbonImmutable::now();
  146.         $this->photos = new ArrayCollection();
  147.         $this->videos = new ArrayCollection();
  148.         $this->providedServices = new ArrayCollection();
  149.         $this->profiles = new ArrayCollection();
  150.     }
  151.     public static function draft(?\DateTimeImmutable $createdAt null): self
  152.     {
  153.         $saloon = new static($createdAt);
  154.         return $saloon;
  155.     }
  156.     public function defineUriIdentity(string $uriIdentity): void
  157.     {
  158.         if (!$this->isDraft()) {
  159.             throw new \DomainException('Saloon is already created and can\'t change its URI.');
  160.         }
  161.         $this->uriIdentity $uriIdentity;
  162.         $this->draft false;
  163.     }
  164.     public function isDraft(): bool
  165.     {
  166.         return $this->draft;
  167.     }
  168.     public function hasOwner(): bool
  169.     {
  170.         return null !== $this->owner;
  171.     }
  172.     public function setNameAndDescription(TranslatableValue $nameTranslatableValue $description): void
  173.     {
  174.         if (!empty($name)) {
  175.             $this->name $name;
  176.         }
  177.         if (!empty($description)) {
  178.             $this->description $description;
  179.         }
  180.     }
  181.     public function setLocation(City $city$stations$districts$address, ?MapCoordinate $mapCoordinate): void
  182.     {
  183.         $this->city $city;
  184.         if (null !== $stations) {
  185.             if (is_array($stations)) {
  186.                 $stations = new ArrayCollection($stations);
  187.             } elseif (!$stations instanceof ArrayCollection) {
  188.                 if (is_iterable($stations)) {
  189.                     $stations = new ArrayCollection(iterator_to_array($stations));
  190.                 } else {
  191.                     throw new \InvalidArgumentException('Stations list should be either an array or an ArrayCollection');
  192.                 }
  193.             }
  194.             $this->stations $stations;
  195.         }
  196.         if (!empty($districts)) {
  197.             $this->districts $districts;
  198.         }
  199.         if (!empty($address)) {
  200.             $this->address $address;
  201.         }
  202.         $this->mapCoordinate $mapCoordinate;
  203.         $this->normalizePrimaryStation();
  204.     }
  205.     private function normalizePrimaryStation(): void
  206.     {
  207.         if ($this->stations->isEmpty()) {
  208.             $this->primaryStation null;
  209.             return;
  210.         }
  211.         if ($this->primaryStation === null || !$this->stations->contains($this->primaryStation)) {
  212.             $this->primaryStation $this->stations->first();
  213.         }
  214.     }
  215.     public function setPhoneCallOptions(string $phoneNumber, ?PhoneCallRestrictions $restrictions, ?Messengers $messengers): void
  216.     {
  217.         $this->phoneNumber $phoneNumber;
  218.         $this->phoneCallRestrictions $restrictions;
  219.         $this->messengers $messengers;
  220.     }
  221.     public function setPricing(?ApartmentsPricing $apartmentsPricing, ?TakeOutPricing $takeOutPricing, ?int $extraCharge, ?ExpressPricing $expressPricing null): void
  222.     {
  223. //        $this->prices = $pricing;
  224.         $this->apartmentsPricing $apartmentsPricing;
  225.         $this->takeOutPricing $takeOutPricing;
  226.         $this->extraCharge $extraCharge;
  227.         $this->expressPricing $expressPricing;
  228.     }
  229.     public function isOwnedBy(Advertiser $account): bool
  230.     {
  231.         return $account->getId() === $this->owner->getId();
  232.     }
  233.     public function getId(): int
  234.     {
  235.         return $this->id;
  236.     }
  237.     public function getOwner(): ?Advertiser
  238.     {
  239.         return $this->owner;
  240.     }
  241.     public function setOwner(Advertiser $owner): void
  242.     {
  243.         $this->owner $owner;
  244.     }
  245.     public function getAdBoardPlacement(): ?AdBoardPlacement
  246.     {
  247.         return $this->adBoardPlacement;
  248.     }
  249.     /**
  250.      * Салон оплачен и выводится в общих списках на сайте
  251.      */
  252.     public function isActive(): bool
  253.     {
  254.         return null !== $this->adBoardPlacement;
  255.     }
  256.     public function getUriIdentity(): string
  257.     {
  258.         return $this->uriIdentity;
  259.     }
  260.     public function getName(): TranslatableValue
  261.     {
  262.         return $this->name;
  263.     }
  264.     public function getDescription(): TranslatableValue
  265.     {
  266.         return $this->description;
  267.     }
  268.     public function getPhoneNumber(): string
  269.     {
  270.         return $this->phoneNumber;
  271.     }
  272.     /**
  273.      * @return Profile[]
  274.      */
  275.     public function getProfiles(): Collection
  276.     {
  277.         return $this->profiles;
  278.     }
  279.     public function addProfile(Profile $profile): void
  280.     {
  281.         if (!$this->profiles->contains($profile)) {
  282.             $this->profiles->add($profile);
  283.         }
  284.         if ($profile->getSaloon() !== $this) {
  285.             $profile->attachToSaloon($this);
  286.         }
  287.     }
  288.     public function removeProfile(Profile $profile): void
  289.     {
  290.         if ($this->profiles->removeElement($profile) && $profile->getSaloon() === $this) {
  291.             $profile->detachFromSaloon();
  292.         }
  293.     }
  294.     public function getWorkingHours(): ?WorkingHours
  295.     {
  296.         return $this->workingHours;
  297.     }
  298.     public function setWorkingHours(?WorkingHours $workingHours): void
  299.     {
  300. //        $this->phoneNumber = $phoneNumber;
  301.         $this->workingHours $workingHours;
  302.     }
  303.     //TODO return type
  304.     public function getEmail(): ?string
  305.     {
  306.         return $this->email;
  307.     }
  308.     public function setEmail(?string $email): void
  309.     {
  310.         $this->email $email;
  311.     }
  312.     public function getPrices(): ?string
  313.     {
  314.         return $this->prices;
  315.     }
  316.     //TODO return type
  317.     public function getApartmentsPricing(): ?ApartmentsPricing
  318.     {
  319.         return $this->apartmentsPricing;
  320.     }
  321.     //TODO return type
  322.     public function getTakeOutPricing(): ?TakeOutPricing
  323.     {
  324.         return $this->takeOutPricing;
  325.     }
  326.     public function getExtraCharge(): ?int
  327.     {
  328.         return $this->extraCharge;
  329.     }
  330.     public function getThumbnail(): ?Thumbnail
  331.     {
  332.         return $this->thumbnail;
  333.     }
  334.     public function setThumbnail(string $path): void
  335.     {
  336.         $this->thumbnail = new Thumbnail($this$path);
  337.     }
  338.     public function getCity(): City
  339.     {
  340.         return $this->city;
  341.     }
  342.     /**
  343.      * @return Station[]
  344.      */
  345.     public function getStations(): Collection
  346.     {
  347.         return $this->stations;
  348.     }
  349.     public function getDistricts(): ?string
  350.     {
  351.         return $this->districts;
  352.     }
  353.     public function getAddress(): TranslatableValue
  354.     {
  355.         return $this->address;
  356.     }
  357.     public function getMapCoordinate(): ?MapCoordinate
  358.     {
  359.         return $this->mapCoordinate;
  360.     }
  361.     public function getUpdatedAt(): ?\DateTimeImmutable
  362.     {
  363.         return $this->updatedAt;
  364.     }
  365.     //TODO return type
  366.     public function setUpdatedAt(\DateTimeImmutable $updatedAt): void
  367.     {
  368.         $this->updatedAt $updatedAt;
  369.     }
  370.     public function addPhoto(string $path): Photo
  371.     {
  372.         $photos $this->getPhotos();
  373.         $found $photos->filter(function (Photo $photo) use ($path): bool {
  374.             return $path === $photo->getPath();
  375.         });
  376.         if (!$found->isEmpty()) {
  377.             return $found->first();
  378.         }
  379.         $photo = new Photo($this$path);
  380.         $this->photos->add($photo);
  381.         return $photo;
  382.     }
  383.     /**
  384.      * @return Photo[]
  385.      */
  386.     public function getPhotos(): Collection
  387.     {
  388.         return $this->photos;
  389.     }
  390.     public function removePhoto(string $path): void
  391.     {
  392.         foreach ($this->getPhotos() as $photo) {
  393.             if ($path === $photo->getPath()) {
  394.                 $this->photos->removeElement($photo);
  395.             }
  396.         }
  397.     }
  398.     public function addVideo(string $path): Video
  399.     {
  400.         $found $this->getVideos()->filter(function (Video $video) use ($path): bool {
  401.             return $path === $video->getPath();
  402.         });
  403.         if (!$found->isEmpty())
  404.             return $found->first();
  405.         $video = new Video($this$path);
  406.         //теперь разрешаем много видео
  407.         //$this->videos->clear();
  408.         $this->videos->add($video);
  409.         return $video;
  410.     }
  411.     /**
  412.      * @return Photo[]
  413.      */
  414.     public function getVideos(): Collection
  415.     {
  416.         return $this->videos;
  417.     }
  418.     public function removeVideo(string $path): void
  419.     {
  420.         foreach ($this->getVideos() as $video) {
  421.             if ($path === $video->getPath()) {
  422.                 $this->videos->removeElement($video);
  423.             }
  424.         }
  425.     }
  426.     public function isMediaProcessed(): bool
  427.     {
  428.         foreach ($this->videos as $video)
  429.             if (null === $video->getPreviewPath())
  430.                 return false;
  431.         return true;
  432.     }
  433.     public function delete(): void
  434.     {
  435.         $this->deletePlacementHiding();
  436.         $this->deleteFromAdBoard();
  437.         $this->setDeletedAt(Carbon::now());
  438.     }
  439.     public function deletePlacementHiding(): void
  440.     {
  441.         $this->placementHiding null;
  442.     }
  443.     public function deleteFromAdBoard(): void
  444.     {
  445.         $this->adBoardPlacement null;
  446.     }
  447.     //TODO return type
  448.     public function undoDelete(): void
  449.     {
  450.         $this->setDeletedAt(); // will pass null by default
  451.     }
  452.     //TODO return type
  453.     public function getPhoneCallRestrictions(): ?PhoneCallRestrictions
  454.     {
  455.         return $this->phoneCallRestrictions;
  456.     }
  457.     public function getExpressPricing(): ?ExpressPricing
  458.     {
  459.         return $this->expressPricing;
  460.     }
  461.     public function getClientTypes(): ?array
  462.     {
  463.         return $this->clientTypes;
  464.     }
  465.     //TODO return type
  466.     /**
  467.      * @param int[] $clientTypes
  468.      */
  469.     public function setClientTypes(?array $clientTypes): void
  470.     {
  471.         $this->clientTypes $clientTypes;
  472.     }
  473.     public function getMessengers(): ?Messengers
  474.     {
  475.         return $this->messengers;
  476.     }
  477.     public function getInactivatedAt(): ?\DateTimeImmutable
  478.     {
  479.         return $this->inactivatedAt;
  480.     }
  481.     public function setInactive(): void
  482.     {
  483.         $this->inactivatedAt CarbonImmutable::now();
  484.     }
  485.     public function undoInactive(): void
  486.     {
  487.         $this->inactivatedAt null;
  488.     }
  489.     public function isHidden(): bool
  490.     {
  491.         return null !== $this->getPlacementHiding();
  492.     }
  493.     public function getPlacementHiding(): ?PlacementHiding
  494.     {
  495.         return $this->placementHiding;
  496.     }
  497.     /**
  498.      * @return CommentByCustomer[]
  499.      */
  500.     public function getComments(): Collection
  501.     {
  502.         return $this->comments->filter(function (CommentByCustomer $comment): bool {
  503.             return null == $comment->getParent();
  504.         });
  505.     }
  506.     /**
  507.      * @return CommentByCustomer[]
  508.      */
  509.     public function getCommentsOrderedByNotReplied(): array
  510.     {
  511.         $comments $this->comments->filter(function (CommentByCustomer $comment): bool {
  512.             return null == $comment->getParent();
  513.         })->toArray();
  514.         usort($comments, function (CommentByCustomer $commentACommentByCustomer $commentB): int {
  515.             if ((null == $commentA->getLastCommentByAdvertiser() && null == $commentB->getLastCommentByAdvertiser())
  516.                 || (null != $commentA->getLastCommentByAdvertiser() && null != $commentB->getLastCommentByAdvertiser())) {
  517.                 if ($commentA->getCreatedAt() == $commentB->getCreatedAt())
  518.                     return $commentA->getId() > $commentB->getId() ? -1;
  519.                 else
  520.                     return $commentA->getCreatedAt() > $commentB->getCreatedAt() ? -1;
  521.             }
  522.             if (null == $commentA->getLastCommentByAdvertiser() && null != $commentB->getLastCommentByAdvertiser())
  523.                 return -1;
  524.             else
  525.                 return 1;
  526.         });
  527.         return $comments;
  528.     }
  529.     public function getCreatedAt(): ?\DateTimeImmutable
  530.     {
  531.         return $this->createdAt;
  532.     }
  533.     /**
  534.      * @return CommentByCustomer[]
  535.      */
  536.     public function getCommentsWithoutReply(): Collection
  537.     {
  538.         return $this->comments->filter(function (CommentByCustomer $comment): bool {
  539.             return null == $comment->getParent() && false == $comment->isCommentedByAdvertiser();
  540.         });
  541.     }
  542.     /**
  543.      * @return CommentByCustomer[]
  544.      */
  545.     public function getCommentsWithReply(): Collection
  546.     {
  547.         return $this->comments->filter(function (CommentByCustomer $comment): bool {
  548.             return null == $comment->getParent() && true == $comment->isCommentedByAdvertiser();
  549.         });
  550.     }
  551.     /**
  552.      * @return CommentByCustomer[]
  553.      */
  554.     public function getNewComments(): Collection
  555.     {
  556.         $weekAgo CarbonImmutable::now()->sub('7 days');
  557.         return $this->comments->filter(function (CommentByCustomer $comment) use ($weekAgo): bool {
  558.             return null == $comment->getParent()
  559.                 && (
  560.                     $comment->getCreatedAt() >= $weekAgo
  561.                     || null == $this->getCommentReply($comment)
  562.                 );
  563.         });
  564.     }
  565.     private function getCommentReply(CommentByCustomer $parent): ?CommentByCustomer
  566.     {
  567.         foreach ($this->comments as $comment)
  568.             if ($comment->getParent() == $parent)
  569.                 return $comment;
  570.         return null;
  571.     }
  572.     public function getOldComments(): Collection
  573.     {
  574.         $weekAgo CarbonImmutable::now()->sub('7 days');
  575.         return $this->comments->filter(function (CommentByCustomer $comment) use ($weekAgo): bool {
  576.             return null == $comment->getParent()
  577.                 && false == (
  578.                     $comment->getCreatedAt() >= $weekAgo
  579.                     || null == $this->getCommentReply($comment)
  580.                 );
  581.         });
  582.     }
  583.     public function getCommentFromUser(Customer $user): ?CommentByCustomer
  584.     {
  585.         foreach ($this->comments as $comment)
  586.             if (null == $comment->getParent() && null != $comment->getUser() && $user->getId() == $comment->getUser()->getId())
  587.                 return $comment;
  588.         return null;
  589.     }
  590.     public function seo(): ?array
  591.     {
  592.         return $this->seo;
  593.     }
  594.     public function seoPhoneNumber(): ?string
  595.     {
  596.         return $this->seo['phone'] ?? null;
  597.     }
  598.     public function setSeoPhoneNumber(string $phoneNumber): void
  599.     {
  600.         if (null === $this->seo) {
  601.             $this->seo = [];
  602.         }
  603.         $this->seo['phone'] = $phoneNumber;
  604.     }
  605.     public function getPrimaryStation(): ?Station
  606.     {
  607.         $station $this->primaryStation ?? $this->getStations()->first();
  608.         if (false === $station) {
  609.             return null;
  610.         }
  611.         return $station;
  612.     }
  613.     public function setPrimaryStation(?Station $station): void
  614.     {
  615.         $this->primaryStation $station;
  616.         $this->normalizePrimaryStation();
  617.     }
  618.     public function getStationsSortedByPrimary(): array
  619.     {
  620.         $stations $this->stations->toArray();
  621.         if (!$this->primaryStation) {
  622.             return $stations;
  623.         }
  624.         usort($stations, function (Station $aStation $b) {
  625.             if ($a->getId() === $this->primaryStation->getId()) return -1;
  626.             if ($b->getId() === $this->primaryStation->getId()) return 1;
  627.             return 0;
  628.         });
  629.         return $stations;
  630.     }
  631.     public function getDeleteMode(): int
  632.     {
  633.         return $this->deleteMode;
  634.     }
  635.     public function setDeleteMode(int $deleteMode): self
  636.     {
  637.         $this->deleteMode $deleteMode;
  638.         return $this;
  639.     }
  640.     public function isHardDeleted(): bool
  641.     {
  642.         return $this->deleteMode === 2;
  643.     }
  644. }