src/Entity/Saloon/Saloon.php line 40

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