src/Entity/Estate.php line 37

Open in your IDE?
  1. <?php
  2. namespace App\Entity;
  3. use Doctrine\Common\Collections\ArrayCollection;
  4. use Doctrine\Common\Collections\Collection;
  5. use Gedmo\Timestampable\Traits\TimestampableEntity;
  6. use Gedmo\SoftDeleteable\Traits\SoftDeleteableEntity;
  7. use App\Repository\EstateRepository;
  8. use Doctrine\ORM\Mapping as ORM;
  9. use Gedmo\Mapping\Annotation as Gedmo;
  10. use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
  11. use Symfony\Component\Validator\Constraints as Assert;
  12. use Symfony\Component\Serializer\Encoder\JsonEncoder;
  13. use Symfony\Component\Serializer\Normalizer\AbstractNormalizer;
  14. use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
  15. use Symfony\Component\Serializer\Serializer;
  16. use Symfony\Component\String\Inflector\FrenchInflector;
  17. use function Symfony\Component\String\u;
  18. use Liip\ImagineBundle\Imagine\Cache\CacheManager;
  19. use Doctrine\ORM\Event\PreUpdateEventArgs;
  20. use App\Utils\EmojiHelper;
  21. /**
  22.  * @ORM\Entity(repositoryClass=EstateRepository::class)
  23.  * @Gedmo\SoftDeleteable(fieldName="deletedAt", timeAware=false, hardDelete=false)
  24.  * @ORM\HasLifecycleCallbacks
  25.  * @UniqueEntity("refannonce")
  26.  */
  27. class Estate
  28. {
  29.     use TimestampableEntity;
  30.     use SoftDeleteableEntity;
  31.     private $imagineCacheManager;
  32.     /**
  33.      * @ORM\Id
  34.      * @ORM\GeneratedValue
  35.      * @ORM\Column(type="integer")
  36.      */
  37.     private $id;
  38.     /**
  39.      * @ORM\Column(type="string", length=255)
  40.      * @Assert\NotBlank
  41.      */
  42.     private $refannonce;
  43.     /**
  44.      * @ORM\Column(type="string", length=255)
  45.      * @Assert\NotBlank
  46.      */
  47.     private $identifiant_technique;
  48.     /**
  49.      * @ORM\Column(type="integer", nullable=true)
  50.      */
  51.     private $numeromandat;
  52.     /**
  53.      * @var \DateTime
  54.      * @ORM\Column( type="datetime", nullable=true)
  55.      */
  56.     private $mandatAt;
  57.     /**
  58.      * @ORM\Column(type="integer", options={"default":1})
  59.      * @Assert\NotBlank
  60.      */
  61.     private $statut;
  62.     /**
  63.      * @ORM\Column(type="string", length=255, options={"default":"available"})
  64.      * @Assert\NotBlank
  65.      */
  66.     private $statut_name;   
  67.    
  68.     /**
  69.      * @Gedmo\Slug(fields={"refannonce", "libelle"})
  70.      * @ORM\Column(type="string", length=255, unique=true)
  71.      */
  72.     private $slug;
  73.     /**
  74.      * @ORM\Column(type="string", length=255)
  75.      */
  76.     private $typebien;
  77.     /**
  78.      * @ORM\Column(type="boolean" , options={"default":0})
  79.      */
  80.     private $si_mandatexclusif;
  81.     /**
  82.      * @ORM\Column(type="string", length=255, nullable=true)
  83.      */
  84.     private $libelle;
  85.     /**
  86.      * @ORM\Column(type="text", nullable=true, options={"collation": "utf8mb4_unicode_ci"})
  87.      */
  88.     private $descriptif;
  89.     /**
  90.      * @ORM\Column(type="float", scale=2,  nullable=true)
  91.      */
  92.     private $prix;
  93.     /**
  94.      * @ORM\Column(type="float", scale=2,  nullable=true)
  95.      */
  96.     private $surface;
  97.     /**
  98.      * @ORM\Column(type="float", scale=2,  nullable=true)
  99.      */
  100.     private $surf_terrain;
  101.     /**
  102.      * @ORM\Column(type="integer", nullable=true)
  103.      */
  104.     private $nbpieces;
  105.     /**
  106.      * @ORM\Column(type="integer", nullable=true)
  107.      */
  108.     private $nbchambres;
  109.     /**
  110.      * @ORM\Column(type="float", nullable=true)
  111.      */
  112.     private $latitude;
  113.     /**
  114.      * @ORM\Column(type="float", nullable=true)
  115.      */
  116.     private $longitude;
  117.     /**
  118.      * @ORM\Column(type="string", length=255, nullable=true)
  119.      */
  120.     private $orientation;
  121.     /**
  122.      * @ORM\Column(type="json", nullable=true)
  123.      */
  124.     private $photos = [];
  125.     /**
  126.      * @ORM\Column(type="json", nullable=true)
  127.      */
  128.     private $features = [];
  129.     /**
  130.      * @ORM\Column(type="json", nullable=true)
  131.      */
  132.     private $icones = [];
  133.     /**
  134.      * @ORM\ManyToOne(targetEntity=Agent::class, inversedBy="estates")
  135.      * @ORM\JoinColumn(nullable=true)
  136.      */
  137.     private $agent;
  138.     /**
  139.      * @ORM\ManyToMany(targetEntity=Agent::class, inversedBy="share_estates" )
  140.      * @ORM\JoinTable(name="share_with_agents")
  141.      */
  142.     private $share_with_agents;
  143.     /**
  144.      * @ORM\ManyToMany(targetEntity=User::class, mappedBy="favorites")
  145.      */
  146.     private $users;
  147.     /**
  148.      * @ORM\ManyToMany(targetEntity=SearchNotification::class, mappedBy="estates")
  149.      */
  150.     private $notifications;
  151.     /**
  152.      * @ORM\Column(type="boolean" , options={"default":0})
  153.      */
  154.     private $is_new_checked;
  155.     /**
  156.      * @ORM\Column(type="boolean" , options={"default":0})
  157.      */
  158.     private $is_delete_checked;
  159.     /**
  160.      * @ORM\Column(type="string", length=10)
  161.      */
  162.     private $import_type;
  163.     private $orientations = ['si_orientenord' => false, 'si_orientesud' => false, 'si_orienteouest' => false, 'si_orienteest'=> false];
  164.     private  $default_features = [
  165.         'localisation' => [
  166.             'adresse' => '',
  167.             'cp' => '',
  168.             'ville' => '',
  169.             'pays' => '',
  170.             'latitude' => '',
  171.             'longitude' => '',
  172.             'cp_reel' => '',
  173.             'ville_reelle' => '',
  174.             'nb_departement' => '',
  175.             'departement' => ''
  176.         ]
  177.     ];
  178.     /**
  179.      * @ORM\ManyToOne(targetEntity=SousType::class, inversedBy="estates")
  180.      * @ORM\JoinColumn(nullable=true)
  181.      */
  182.     private $sous_type;
  183.     /**
  184.      * @ORM\Column(type="float", nullable=true)
  185.      */
  186.     private $ca;
  187.     /**
  188.      * @ORM\Column(type="float", nullable=true)
  189.      */
  190.     private $ebe;
  191.     public function __construct()
  192.     {
  193.         $this->users = new ArrayCollection();
  194.         $this->notifications = new ArrayCollection();
  195.         $this->share_with_agents = new ArrayCollection();
  196.     }
  197.     public function __toString() {
  198.         return $this->refannonce;
  199.     }
  200.     public function setImagineCacheManager(CacheManager $imagineCacheManager) {
  201.         $this->imagineCacheManager = $imagineCacheManager;
  202.     }
  203.     public function getName(): ?string
  204.     {
  205.         return $this->refannonce;
  206.     }
  207.     public function getId(): ?int
  208.     {
  209.         return $this->id;
  210.     }
  211.     public function getRefannonce(): ?string
  212.     {
  213.         return $this->refannonce;
  214.     }
  215.     public function setRefannonce(string $refannonce): self
  216.     {
  217.         $this->refannonce = $refannonce;
  218.         return $this;
  219.     }
  220.     public function getIdentifiantTechnique(): ?string
  221.     {
  222.         return $this->identifiant_technique;
  223.     }
  224.     public function setIdentifiantTechnique(string $identifiant_technique): self
  225.     {
  226.         $this->identifiant_technique = $identifiant_technique;
  227.         return $this;
  228.     }
  229.     public function getNumeromandat(): ?int
  230.     {
  231.         return $this->numeromandat;
  232.     }
  233.     public function setNumeromandat(?int $numeromandat): self
  234.     {
  235.         $this->numeromandat = $numeromandat;
  236.         return $this;
  237.     }
  238.     public function getMandatAt(): ?\DateTimeInterface
  239.     {      
  240.         return $this->mandatAt;
  241.     }
  242.     public function setMandatAt($mandatAt=null): self
  243.     {   
  244.         if(!is_null($mandatAt)){
  245.             $mandatAt = new \DateTime ($mandatAt);
  246.             $mandatAt->setTime(0, 0, 0);
  247.         }
  248.         // Empêche la modification si la valeur est identique cat l'objet DateTime est diffrérent
  249.         if($mandatAt != $this->mandatAt){
  250.             $this->mandatAt = $mandatAt;
  251.         }
  252.         return $this;
  253.     }
  254.     
  255.     public function setDateMandat($date): self
  256.     {   
  257.         $this->setMandatAt($date);
  258.         return $this;
  259.     }
  260.     public function getMandatAtFormated() 
  261.     {   
  262.         $mandatAt = $this->getMandatAt();
  263.         return $mandatAt ? $mandatAt->format('d/m/Y') : null;
  264.     }
  265.     public function getStatut(): ?string
  266.     {
  267.         return $this->convertedValue('statut', $this->statut);
  268.         // return $this->statut;
  269.     }
  270.     
  271.     public function getStatutRaw(): ?string
  272.     {
  273.         return $this->statut;
  274.     }
  275.     public function setStatut(int $statut): self
  276.     {
  277.         $this->statut = $statut;
  278.         
  279.         return $this;
  280.     }
  281.     public function getStatutName(): ?string
  282.     {
  283.         return $this->convertedValue('statut_name', $this->statut_name);
  284.         // return $this->statut_name;
  285.     }
  286.     public function getStatutNameRaw(): ?string
  287.     {
  288.         return $this->statut_name;
  289.     }
  290.     public function setStatutName(string $statut_name): self
  291.     {
  292.         $this->statut_name = $statut_name;
  293.         return $this;
  294.     }
  295.     public function getSlug(): ?string
  296.     {
  297.         return $this->slug;
  298.     }
  299.     public function setSlug(string $slug): self
  300.     {
  301.         $this->slug = $slug;
  302.         return $this;
  303.     }
  304.     public function getTypebienRaw(): ?string
  305.     {
  306.         return $this->typebien;
  307.     }
  308.     public function getTypebien(): ?string
  309.     {
  310.         $types = array_flip(self::getTypes());
  311.         return isset($types[$this->typebien])? $types[$this->typebien] : u( $this->typebien )->title();
  312.     }
  313.     public function setTypebien(string $typebien): self
  314.     {
  315.         $this->typebien = $typebien;
  316.         return $this;
  317.     }
  318.     public function getSiMandatexclusif(): ?bool
  319.     {
  320.         return $this->si_mandatexclusif;
  321.     }
  322.     public function setSiMandatexclusif(bool $si_mandatexclusif): self
  323.     {
  324.         $this->si_mandatexclusif = $si_mandatexclusif;
  325.         return $this;
  326.     }
  327.     
  328.     public function getLibelle(): ?string
  329.     {   
  330.         return $this->getTitle();
  331.     }
  332.     public function setLibelle(?string $libelle): self
  333.     {
  334.         $this->libelle = $libelle;
  335.         return $this;
  336.     }
  337.     public function getDescriptif(): ?string
  338.     {   
  339.         //enleve les emoticons
  340.         // $this->descriptif = $this->removeEmojis($this->descriptif);
  341.         // $this->descriptif = strip_tags($this->descriptif, '<sup>,<br>,<p>');
  342.         return $this->descriptif;
  343.     }
  344.     public function setDescriptif(?string $descriptif): self
  345.     {   
  346.         //corrections
  347.         $descriptif = str_replace('SOUS OFRE', 'SOUS OFFRE',  $descriptif);
  348.         $mentions = [
  349.             'sous offre',
  350.             'sous compromis',
  351.             'vendu',
  352.             'en vente'
  353.         ];
  354.         
  355.         // Pour chaque mention, on supprime les variantes au début ou dans le texte avec la présence des signes : .:/- 
  356.         foreach ($mentions as $mention) {
  357.             $descriptif = preg_replace(
  358.                 // '#/?/?\s*' . preg_quote($mention, '#') . '\s*[.:/-]*\s*/?/?#i',
  359.                 '#(?<=^|[\s/:\-\.])' . preg_quote($mention, '#') . '(?=[\s/:\-\.]|$)#i',
  360.                 '',
  361.                 $descriptif
  362.             );
  363.         }
  364.         //supprime les /// ou, /// avec ou sans espace
  365.         $descriptif = preg_replace('#\s*/{2,}\s*#', '', $descriptif);
  366.         //suppime les espaces double
  367.         $descriptif = trim(preg_replace('/\s{2,}/', ' ', $descriptif));
  368.         //supprime les sauts de ligne en début de chaine
  369.         $descriptif = preg_replace('#^(<br\s*/?>\s*)+#i', '', $descriptif);
  370.         //supprime les espaces au début et à la fin
  371.         $descriptif = trim($descriptif);        
  372.         //ajoute un espace après un signe de ponctuation [.!?] suivi d'un caractère
  373.         $descriptif = preg_replace('#([.!?])(\S)#', '$1 $2', $descriptif);
  374.         
  375.         //m2 => m²
  376.         $descriptif =  preg_replace('#m2#', 'm²', $descriptif);
  377.         // Supprime uniquement les &nbsp; (et espaces normaux) en début de chaîne
  378.         $descriptif = preg_replace('/^(?:&nbsp;|\s)+/i', '', $descriptif);
  379.         //Netoyage HTL , mais conserve <sup>,<br>,<p>
  380.         $descriptif = strip_tags($descriptif, '<sup>,<br>,<p>');
  381.         // Supprimer les <p> vides ou contenant seulement <br> ou des espaces
  382.         $descriptif = preg_replace('#<p>\s*(<br\s*/?>)?\s*</p>#i','',$descriptif);
  383.         // Supprimer les multiples sauts de ligne inutiles
  384.         $descriptif = preg_replace("/\n\s*\n/", "\n", $descriptif);
  385.         $this->descriptif = $descriptif;
  386.         return $this;
  387.     }
  388.     private function containsEmoji(string $text): bool {
  389.         return preg_match(
  390.             '/[\x{1F600}-\x{1F64F}' .  // Emoticons
  391.             '\x{1F300}-\x{1F5FF}' .  // Symbols & pictographs
  392.             '\x{1F680}-\x{1F6FF}' .  // Transport & map
  393.             '\x{1F1E0}-\x{1F1FF}' .  // Flags
  394.             '\x{2600}-\x{26FF}' .    // Misc symbols
  395.             '\x{2700}-\x{27BF}' .    // Dingbats
  396.             '\x{1F900}-\x{1F9FF}' .  // Supplemental symbols
  397.             '\x{1FA70}-\x{1FAFF}' .  // Symbols & pictographs extended-A
  398.             '\x{1F018}-\x{1F270}' .  // Playing cards, enclosed
  399.             '\x{238C}-\x{2454}' .    // Misc technical
  400.             '\x{20D0}-\x{20FF}' .    // Combining Diacritical Marks for Symbols
  401.             '\x{FE00}-\x{FE0F}' .    // Variation Selectors
  402.             '\x{1F000}-\x{1F02F}' .  // Mahjong & domino
  403.             '\x{1F1F2}-\x{1F1F4}' .  // Flags (regional)
  404.             '\x{1F1E6}-\x{1F1FF}]' . // Country flags
  405.             '/u',$text);
  406.     }
  407.     private function removeEmojis(string $text): string {
  408.         return preg_replace(
  409.             '/[\x{1F600}-\x{1F64F}' .  // Emoticons
  410.             '\x{1F300}-\x{1F5FF}' .  // Symbols & pictographs
  411.             '\x{1F680}-\x{1F6FF}' .  // Transport & map
  412.             '\x{1F1E0}-\x{1F1FF}' .  // Flags
  413.             '\x{2600}-\x{26FF}' .    // Misc symbols
  414.             '\x{2700}-\x{27BF}' .    // Dingbats
  415.             '\x{1F900}-\x{1F9FF}' .  // Supplemental symbols
  416.             '\x{1FA70}-\x{1FAFF}' .  // Symbols & pictographs extended-A
  417.             '\x{1F018}-\x{1F270}' .  // Playing cards, enclosed
  418.             '\x{238C}-\x{2454}' .    // Misc technical
  419.             '\x{20D0}-\x{20FF}' .    // Combining Diacritical Marks for Symbols
  420.             '\x{FE00}-\x{FE0F}' .    // Variation Selectors
  421.             '\x{1F000}-\x{1F02F}' .  // Mahjong & domino
  422.             '\x{1F1F2}-\x{1F1F4}' .  // Flags (regional)
  423.             '\x{1F1E6}-\x{1F1FF}]' . // Country flags
  424.             '/u', '', $text);
  425.     }
  426.     public function getPrix(): ?float
  427.     {
  428.         return $this->prix;
  429.     }
  430.     public function setPrix(?float $prix): self
  431.     {
  432.         $this->prix = $prix;
  433.         return $this;
  434.     }
  435.     public function getSurface(): ?float
  436.     {
  437.         return $this->surface;
  438.     }
  439.     public function setSurface(?float $surface): self
  440.     {
  441.         $this->surface = $surface;
  442.         return $this;
  443.     }
  444.     public function getSurfTerrain(): ?float
  445.     {
  446.         return $this->surf_terrain;
  447.     }
  448.     public function setSurfTerrain(?float $surf_terrain): self
  449.     {
  450.         $this->surf_terrain = $surf_terrain;
  451.         return $this;
  452.     }
  453.     public function getNbpieces(): ?int
  454.     {
  455.         return $this->nbpieces;
  456.     }
  457.     public function setNbpieces(?int $nbpieces): self
  458.     {
  459.         $this->nbpieces = $nbpieces;
  460.         return $this;
  461.     }
  462.     public function getNbchambres(): ?int
  463.     {
  464.         return $this->nbchambres;
  465.     }
  466.     public function setNbchambres(?int $nbchambres): self
  467.     {
  468.         $this->nbchambres = $nbchambres;
  469.         return $this;
  470.     }
  471.     public function getLatitude(): ?string
  472.     {
  473.         // return $this->features['localisation']['latitude'];
  474.         return $this->latitude;    
  475.     }
  476.     public function setLatitude(?float $latitude): self
  477.     {
  478.         $this->latitude = $latitude;
  479.         return $this;
  480.     }
  481.     public function getLongitude(): ?string
  482.     {
  483.         // return $this->features['localisation']['longitude'];
  484.         return $this->longitude;      
  485.     }
  486.     public function setLongitude(?float $longitude): self
  487.     {
  488.         $this->longitude = $longitude;
  489.         return $this;
  490.     }
  491.     public function getOrientation(): ?string
  492.     {
  493.         return $this->orientation;
  494.     }
  495.     public function setOrientation(?string $orientation): self
  496.     {
  497.         $this->orientation = $orientation;
  498.         return $this;
  499.     }
  500.     public function getPhotos(): ?array
  501.     {
  502.         return is_null($this->photos) ? [] : $this->photos;
  503.     }
  504.     public function setPhotos(?array $photos): self
  505.     {
  506.         $this->photos = $photos;
  507.         return $this;
  508.     }
  509.     public function getFeatures(): ?array
  510.     {
  511.         return $this->features;
  512.     }
  513.     public function setFeatures(?array $features): self
  514.     {
  515.         $this->features = $features;
  516.         return $this;
  517.     }
  518.     public function getIcones(): ?array
  519.     {   
  520.         $this->icones['nbsdeau_sdb'] = (int) $this->icones['nbsdeau'] + (int) $this->icones['nbsdb'];
  521.         
  522.         return $this->icones;
  523.     }
  524.     public function setIcones(?array $icones): self
  525.     {
  526.         $this->icones = $icones;
  527.         return $this;
  528.     }
  529.     public function getAgent(): ?Agent
  530.     {
  531.         return $this->agent;
  532.     }
  533.     public function setAgent(?Agent $agent): self
  534.     {
  535.         $this->agent = $agent;
  536.         return $this;
  537.     }
  538.     public function getIsNewChecked(): ?bool
  539.     {
  540.         return $this->is_new_checked;
  541.     }
  542.     public function setIsNewChecked(bool $is_new_checked): self
  543.     {
  544.         $this->is_new_checked = $is_new_checked;
  545.         return $this;
  546.     }
  547.     public function getIsDeleteChecked(): ?bool
  548.     {
  549.         return $this->is_delete_checked;
  550.     }
  551.     public function setIsDeleteChecked(bool $is_delete_checked): self
  552.     {
  553.         $this->is_delete_checked = $is_delete_checked;
  554.         return $this;
  555.     }
  556.     public function getImportType(): ?string
  557.     {
  558.         return $this->import_type;
  559.     }
  560.     public function setImportType(string $import_type): self
  561.     {
  562.         $this->import_type = $import_type;
  563.         return $this;
  564.     }
  565.     //METHODS --------------------------------------------------------------
  566.     public function getCountPhotos(): ?int
  567.     {   
  568.         $photos = $this->getPhotos();
  569.         $nb_photos = is_countable($photos) ? count($photos) : 0;
  570.         return $nb_photos%2 != 0 ? $nb_photos : $nb_photos - 1;
  571.     }
  572.     public function getPhotoForStream($index): ?string
  573.     {   
  574.         if( isset($this->photos[$index]) ){
  575.             //remove (http:// ou https://)
  576.             return preg_replace("#^[^:/.]*[:/]+#i", '',$this->photos[$index]);
  577.         }
  578.         else{
  579.             return null;
  580.         }
  581.     }
  582.     public function preparefirstPhoto(): ?array
  583.     {  
  584.         $photo_path = $this->getPhotoForStream(0);
  585.         if (is_null($photo_path)) {
  586.             return null; // ou un placeholder par défaut
  587.         }   
  588.         $formats = ['stream_estate_lazy','stream_estate_thumb','stream_estate_infobox_tiny'];
  589.         $browserPaths = [];
  590.         foreach($formats as $format){
  591.             $browserPaths[] = $this->imagineCacheManager->getBrowserPath($photo_path, $format);
  592.         }
  593.         return $browserPaths;
  594.         
  595.     }
  596.     public function getCover(): ?string
  597.     {   
  598.         return $this->getPhotoForStream(0);
  599.     }
  600.     public function getPhotoThumb($index, $format="stream_estate_thumb"): ?string
  601.     {  
  602.         $photo_path = $this->getPhotoForStream($index);
  603.         if (is_null($photo_path)) {
  604.             return null; // ou un placeholder par défaut
  605.         }   
  606.         return $this->imagineCacheManager->getBrowserPath($photo_path,  $format);
  607.     }
  608.     public function getCoverThumb($format='stream_estate_thumb'): ?string
  609.     {
  610.         return $this->getPhotoThumb(0, $format);
  611.     }
  612.     public function getCoverLazyThumb($format='stream_estate_lazy'): ?string
  613.     {
  614.         return $this->getPhotoThumb(0, $format);
  615.     }
  616.     public function getCoverInfoBox(): ?string
  617.     {
  618.         return $this->getCoverThumb('stream_estate_infobox_tiny');
  619.     }
  620.     public function getPhotosThumb(): ?array
  621.     {  
  622.         $thumbs = [];
  623.         $photos = $this->getPhotos();
  624.         foreach ($photos as $index => $photo) {
  625.             //il faut un nombre impair
  626.             if( $index ==  count($photos) - 1 && $index%2 != 0 ){
  627.             }
  628.             else{
  629.                 $thumbs[] = [
  630.                     'lazy' => $this->imagineCacheManager->getBrowserPath($this->getPhotoForStream($index),"stream_estate_lazy"),
  631.                     'modal' => $this->imagineCacheManager->getBrowserPath($this->getPhotoForStream($index),"stream_estate_thumb"),
  632.                     'large' => $this->imagineCacheManager->getBrowserPath($this->getPhotoForStream($index),"stream_estate_large"),
  633.                 ];
  634.             }
  635.         }
  636.         if(count($thumbs) > 0 && count($thumbs) < 7){
  637.             $less = 7 - count($thumbs) ;
  638.             for($i=0; $i<$less; $i++){
  639.                 $thumbs[] = $thumbs[$i];
  640.             }
  641.         }
  642.         // dump($thumbs); die;
  643.         return $thumbs;
  644.     }
  645.     public function getPhotosCarousel(): ?array
  646.     {  
  647.         $thumbs = [];
  648.         $photos = array_slice($this->getPhotos(),0,5);
  649.         foreach ($photos as $index => $photo) {
  650.             $thumbs[] = [
  651.                 'lazy' => $this->imagineCacheManager->getBrowserPath($this->getPhotoForStream($index),"stream_estate_lazy"),
  652.                 'thumb' => $this->imagineCacheManager->getBrowserPath($this->getPhotoForStream($index),"stream_estate_thumb"),
  653.             ];
  654.         
  655.         }
  656.         return $thumbs;
  657.     }
  658.     public function getAgentThumb($format='agent_thumb'): ?string
  659.     {
  660.         return $this->getAgent()->getThumb($format);
  661.     }
  662.     public function getAgentThumbMedium(): ?string
  663.     {
  664.         return $this->getAgentThumb('agent_thumb_medium');
  665.     }
  666.     public function getAgentThumbSmall(): ?string
  667.     {
  668.         return $this->getAgentThumb('agent_thumb_small');
  669.     }
  670.     public function initForImport($import_type){
  671.         $this->import_type = $import_type;
  672.         $this->features = $this->default_features;
  673.         $this->photos = [];
  674.     }
  675.     public function addFeature($key , $value){
  676.         $this->features[$key] = $value;
  677.     }
  678.     public function addIcone($key , $value){
  679.         if (substr($key, 0, 3) === 'si_') {
  680.             $value = ($value !== null && $value >= 1) ? true : false; 
  681.         }
  682.         $this->icones[$key] = $value;
  683.     }
  684.     public function addPhoto( $value){
  685.         if(!empty($value) ){
  686.             $this->photos[] = $value;
  687.         }
  688.     }
  689.     public function addLocalisation($key , $value){
  690.         // if($key == 'cp_reel' && $value !='' ){
  691.         //     $nb_departement = substr($value ,0,2);
  692.         //     $this->features['localisation']['nb_departement'] = $nb_departement;
  693.         //     $this->features['localisation']['departement'] = self::getDepartement($nb_departement);
  694.         // }
  695.         $this->features['localisation'][$key] = $value;
  696.     }
  697.     public function addOrientation($key , $value){
  698.         $this->orientations[$key] = $value;
  699.         $this->features['orientation'] = '';
  700.         $orientations = [];
  701.         foreach ($this->orientations as $key => $value) {
  702.             if($value){
  703.                 $orientations[] = $this->convertedValue('orientation' , $key);
  704.             }
  705.         }
  706.         // $this->features['orientation'] = implode('/', $orientations);
  707.         $this->setOrientation(implode('/', $orientations));
  708.     }
  709.     public function addConvert($key , $value){
  710.         $value = $this->convertedValue( $key, $value);
  711.         $this->features[$key] = $value;
  712.     }
  713.     public function convertedValue($key , $value){
  714.         $values = [
  715.             "orientation" => [
  716.                 'si_orientenord' => 'Nord', 
  717.                 'si_orientesud' => 'Sud', 
  718.                 'si_orienteouest' => 'Ouest', 
  719.                 'si_orienteest'=> 'Est'
  720.             ],
  721.             "typechauffage" => [
  722.                 "128" => "Par radiateur",
  723.                 "256" => "Au sol",
  724.                 "384" => "Sol et radiateurs",
  725.                 "512" => "Gaz",
  726.                 "640" => "Gaz - Radiateurs",
  727.                 "768" => "Gaz - Au sol",
  728.                 "896" => "Gaz - Sol et radiateurs",
  729.                 "1024" => "Fuel",
  730.                 "1152" => "Fuel - Radiateurs",
  731.                 "1280" => "Fuel - Au sol",
  732.                 "1408" => "Fuel - Sol et radiateurs",
  733.                 "2048" => "Électrique",
  734.                 "2176" => "Électrique - Radiateurs",
  735.                 "2304" => "Électrique - Au sol",
  736.                 "2432" => "Électrique - Sol et radiateurs",
  737.                 "4096" => "Collectif",
  738.                 "4224" => "Collectif par radiateur",
  739.                 "4352" => "Collectif au sol",
  740.                 "4480" => "Collectif au sol et radiateurs",
  741.                 "4608" => "Collectif au gaz",
  742.                 "4736" => "Collectif au gaz - Radiateurs",
  743.                 "4864" => "Collectif au gaz - Au sol",
  744.                 "4992" => "Collectif gaz - Sol & radiateurs",
  745.                 "5120" => "Collectif au fuel",
  746.                 "5248" => "Collectif au fuel - Radiateurs",
  747.                 "5376" => "Collectif au fuel - Au sol",
  748.                 "5504" => "Collectif fuel - Sol & radiateurs",
  749.                 "6144" => "Collectif électrique",
  750.                 "6272" => "Collectif électrique - Radiateurs",
  751.                 "6400" => "Collectif électrique - Au sol",
  752.                 "6528" => "Collectif électrique - Mixte",
  753.                 "8192" => "Individuel",
  754.                 "8320" => "Radiateurs",
  755.                 "8576" => "Au sol & radiateurs",
  756.                 "8704" => "Gaz",
  757.                 "8832" => "Gaz - Radiateurs",
  758.                 "8960" => "Gaz - Au sol",
  759.                 "9088" => "Gaz - Sol & radiateurs",
  760.                 "9216" => "Fuel",
  761.                 "9344" => "Fuel - Radiateurs",
  762.                 "9472" => "Fuel - Au sol",
  763.                 "9600" => "Fuel - Sol & radiateurs",
  764.                 "10240" => "Électrique",
  765.                 "10368" => "Électrique - Radiateurs",
  766.                 "10496" => "Électrique - Au sol",
  767.                 "10624" => "Électrique - Sol et radiateurs",
  768.                 "16384" => "Climatisation reversible",
  769.                 "20480" => "Climatisation centralisée",
  770.                 "24576" => "Climatisation Individuelle"
  771.             ],
  772.             "typecuisine" => [
  773.                 "1" => "Aucune",
  774.                 "2" => "Ouverte",
  775.                 "3" => "Séparée",
  776.                 "4" => "Industrielle",
  777.                 "5" => "Coin cuisine",
  778.                 "6" => "Aménagée & équipée",
  779.                 "7" => "Fermée",
  780.                 "8" => "Coin cuisine équipé",
  781.                 "9" => "Équipée",
  782.             ],
  783.             "honoraires_charges_de" => [
  784.                 "1" => "Acquéreur",
  785.                 "2" => "Vendeur",
  786.                 "3" => "Acquéreur ET Vendeur",
  787.             ],
  788.             "statut_csv" => [ //csv
  789.                 "1" => "En estimation", // (ne sera pas diffusé car champs 112 "mandat" sera Null), affiche le prix
  790.                 "2" => "En vente", // affiche le prix
  791.                 "3" => "Sous offre", // (bandeau Ribbon wrapped)
  792.                 "4" => "Sous compromis", // (bandeau Ribbon wrapped)
  793.                 "5" => "Vendu", // (bandeau Ribbon wrapped)
  794.             ],
  795.             "statut" => [ //netty
  796.                 "1" => "En vente", // En vente Sur le marché: affiche le prix
  797.                 "2" => "Sous compromis", // (bandeau Ribbon wrapped)  
  798.                 "3" => "Vendu", // (bandeau Ribbon wrapped)
  799.                 "4" => "Retiré", // non diffusé
  800.                 "5" => "Réservé", // ???
  801.                 "6" => "Sous offre", // (bandeau Ribbon wrapped)
  802.                 "9" => "Archivé", // non diffusé
  803.             ],
  804.             "statut_name" => [
  805.                 "available" => "En vente", // Sur le marché: affiche le prix
  806.                 "under_contract" => "Sous compromis", // (bandeau Ribbon wrapped)  
  807.                 "sold" => "Vendu", // (bandeau Ribbon wrapped)
  808.                 "withdrawn" => "Retiré", // non diffusé
  809.                 "reserved" => "Réservé", // ???
  810.                 "under_offer" => "Sous offre", // (bandeau Ribbon wrapped)
  811.                 "archived" => "Archivé", // non diffusé
  812.                 'rented' => 'Loué',
  813.                 'expired' => 'Expiré',    
  814.             ],
  815.         ];
  816.         return isset($values[$key][$value]) ? $values[$key][$value] : "";   
  817.     }
  818.     public static function getTypes($familly_type=null, $unsets=[]): ?array 
  819.     {
  820.         switch ($familly_type){
  821.             case 'acheter';
  822.                 $types = [
  823.                     'Appartements'      => 'appartement',
  824.                     'Studios'           => 'studio',
  825.                     'Lofts / Ateliers'  => 'loft/atelier/surface',
  826.                     'Maisons'           => 'maison/villa',
  827.                     'Maisons'           => 'maison',
  828.                     'Terrains'          => 'terrain',
  829.                     'Parking/box'       => 'parking/box',
  830.                     'Immeubles'         => 'immeuble',
  831.                     'Châteaux'          => 'chateau',
  832.                     // 'Divers'            => 'inconnu'
  833.                 ];
  834.             break;
  835.             case 'commerces':
  836.                 $types = [
  837.                     'Fonds de commerce'=> 'boutique',
  838.                     'Entreprise' => 'entreprise',
  839.                     'Bureaux'=> 'bureaux',
  840.                     'Entrepôt' => 'entrepot',
  841.                     'Locaux professionnels' => 'local',
  842.                     // 'Divers'            => 'inconnu'
  843.                 ];
  844.             break;    
  845.             default:
  846.                 $types = [
  847.                     'Appartement'           => 'appartement', 
  848.                     'Studio'                => 'studio', 
  849.                     'Loft / Atelier'        => 'loft/atelier/surface', 
  850.                     'Maison'                => 'maison/villa', 
  851.                     'Maison'                => 'maison',
  852.                     'Terrain'               => 'terrain',
  853.                     'Parking/box'           => 'parking/box',
  854.                     'Immeuble'              => 'immeuble',
  855.                     'Château'               => 'chateau',
  856.                     'Fonds de commerce'      => 'boutique',
  857.                     'Local professionnel'   => 'local',
  858.                     'Bureau'                => 'bureaux',
  859.                     // 'Divers'                => 'inconnu'
  860.                 ];
  861.             break;
  862.         }
  863.         if(count($unsets) > 0){
  864.             foreach($unsets as $unset){
  865.                 unset($types[$unset]);
  866.             }
  867.         }
  868.        return $types;           
  869.     }
  870.     public static function getIds($estates): ?array 
  871.     {   
  872.         $ids = [];
  873.         foreach($estates as $estate){
  874.             $ids[] = $estate->getId();
  875.         }
  876.         return $ids;
  877.     }
  878.     public static function encode($estates): ?array 
  879.     {   
  880.         $encoders = [new JsonEncoder()];
  881.         $defaultContext = [
  882.             AbstractNormalizer::CIRCULAR_REFERENCE_HANDLER => function ($object, $format, $context) {
  883.                 return $object->getName();
  884.             },
  885.         ];
  886.         $normalizers = [new ObjectNormalizer(null, null, null, null, null, null, $defaultContext)];
  887.         $serializer = new Serializer($normalizers, $encoders);
  888.         $normalized =   $serializer->normalize($estates, null, [AbstractNormalizer::ATTRIBUTES => [
  889.             'id',
  890.             'numeromandat',
  891.             'refannonce',
  892.             'siNuPropriete',
  893.             'siMandatexclusif',
  894.             'slug',
  895.             'statut',
  896.             'statutName',
  897.             'typebien',
  898.             'title',
  899.             'libelle',
  900.             'libelleCourt',
  901.             'descriptif',
  902.             'descriptifCourt',
  903.             'prix',
  904.             'surface',
  905.             'surf_terrain',
  906.             'nbpieces',
  907.             'nbchambres',
  908.             'photosThumb',
  909.             'photosCarousel',
  910.             'features',
  911.             'icones',
  912.             'cover',
  913.             'countPhotos',
  914.             'countThumbPhotos',
  915.             'statut',
  916.             'coverThumb',
  917.             'coverLazyThumb',
  918.             'coverInfoBox',
  919.             'agentThumbSmall',
  920.             'agentThumbMedium',
  921.             'latitude',
  922.             'longitude',
  923.             'publicFeatures',
  924.             'publicIcones',
  925.             'pecLetters',
  926.             'location',
  927.             'withMap',
  928.             'agent' => ['id', 'name', 'slug', 'photo', 'email', 'telephone', 'whatsapp', 'rating', 'countReviews']
  929.         ]]);
  930.         return $normalized;
  931.     }
  932.     public  function getLocation()
  933.     {   
  934.         $feats = $this->getFeatures();
  935.         $localisation = $feats['localisation'];
  936.         $nb_departement = substr($localisation['cp_reel'] ,0,2);
  937.         $departement = self::getDepartement($nb_departement);
  938.         
  939.         return $localisation['ville'] != '' ?  $localisation['ville'] : $departement;
  940.     }
  941.     public  function getWithMap()
  942.     {
  943.         return !in_array($this->getTypebienRaw() , self::getTypes('commerces')) && $this->getLatitude() > 0;
  944.     }
  945.     public static function getDepartement($nb)
  946.     {
  947.         $departements = [
  948.         1 => "Ain",
  949.         2 => "Aisne",
  950.         3 => "Allier",
  951.         4 => "Alpes-de-Haute-Provence",
  952.         5 => "Hautes-Alpes",
  953.         6 => "Alpes-Maritimes",
  954.         7 => "Ardèche",
  955.         8 => "Ardennes",
  956.         9 => "Ariège",
  957.         10 => "Aube",
  958.         11 => "Aude",
  959.         12 => "Aveyron",
  960.         13 => "Bouches-du-Rhône",
  961.         14 => "Calvados",
  962.         15 => "Cantal",
  963.         16 => "Charente",
  964.         17 => "Charente-Maritime",
  965.         18 => "Cher",
  966.         19 => "Corrèze",
  967.         20 => "Corse",
  968.         21 => "Côte-d'Or",
  969.         22 => "Côtes-d'Armor",
  970.         23 => "Creuse",
  971.         24 => "Dordogne",
  972.         25 => "Doubs",
  973.         26 => "Drôme",
  974.         27 => "Eure",
  975.         28 => "Eure-et-Loir",
  976.         29 => "Finistère",
  977.         30 => "Gard",
  978.         31 => "Haute-Garonne",
  979.         32 => "Gers",
  980.         33 => "Gironde",
  981.         34 => "Hérault",
  982.         35 => "Ille-et-Vilaine",
  983.         36 => "Indre",
  984.         37 => "Indre-et-Loire",
  985.         38 => "Isère",
  986.         39 => "Jura",
  987.         40 => "Landes",
  988.         41 => "Loir-et-Cher",
  989.         42 => "Loire",
  990.         43 => "Haute-Loire",
  991.         44 => "Loire-Atlantique",
  992.         45 => "Loiret",
  993.         46 => "Lot",
  994.         47 => "Lot-et-Garonne",
  995.         48 => "Lozère",
  996.         49 => "Maine-et-Loire",
  997.         50 => "Manche",
  998.         51 => "Marne",
  999.         52 => "Haute-Marne",
  1000.         53 => "Mayenne",
  1001.         54 => "Meurthe-et-Moselle",
  1002.         55 => "Meuse",
  1003.         56 => "Morbihan",
  1004.         57 => "Moselle",
  1005.         58 => "Nièvre",
  1006.         59 => "Nord",
  1007.         60 => "Oise",
  1008.         61 => "Orne",
  1009.         62 => "Pas-de-Calais",
  1010.         63 => "Puy-de-Dôme",
  1011.         64 => "Pyrénées-Atlantiques",
  1012.         65 => "Hautes-Pyrénées",
  1013.         66 => "Pyrénées-Orientales",
  1014.         67 => "Bas-Rhin",
  1015.         68 => "Haut-Rhin",
  1016.         69 => "Rhône",
  1017.         70 => "Haute-Saône",
  1018.         71 => "Saône-et-Loire",
  1019.         72 => "Sarthe",
  1020.         73 => "Savoie",
  1021.         74 => "Haute-Savoie",
  1022.         75 => "Paris",
  1023.         76 => "Seine-Maritime",
  1024.         77 => "Seine-et-Marne",
  1025.         78 => "Yvelines",
  1026.         79 => "Deux-Sèvres",
  1027.         80 => "Somme",
  1028.         81 => "Tarn",
  1029.         82 => "Tarn-et-Garonne",
  1030.         83 => "Var",
  1031.         84 => "Vaucluse",
  1032.         85 => "Vendée",
  1033.         86 => "Vienne",
  1034.         87 => "Haute-Vienne",
  1035.         88 => "Vosges",
  1036.         89 => "Yonne",
  1037.         90 => "Territoire de Belfort",
  1038.         91 => "Essonne",
  1039.         92 => "Hauts-de-Seine",
  1040.         93 => "Seine-Saint-Denis",
  1041.         94 => "Val-de-Marne",
  1042.         95 => "Val-d'Oise",
  1043.         971 => "Guadeloupe",
  1044.         972 => "Martinique",
  1045.         973 => "Guyane",
  1046.         974 => "La Réunion",
  1047.         976 => "Mayotte"
  1048.         ];
  1049.         return isset($departements[$nb]) ? $departements[$nb] : '';
  1050.     }
  1051.     public function getTitle(){
  1052.         return trim(implode(' ', $this->getInfosTitle())) ;
  1053.     }
  1054.     public function getInfosTitle(){
  1055.         $feats = $this->getFeatures();
  1056.         $icones =  $this->getIcones();
  1057.         $infos_title[] = isset($feats['soustype_bien']) && $feats['soustype_bien'] != "" && $feats['soustype_bien'] != 'constructible' ? ucfirst($feats['soustype_bien'] ):  $this->getTypebien();
  1058.         
  1059.         //terrain
  1060.         if($this->typebien == "terrain"){
  1061.             if( isset($icones['si_constructible']) && $icones['si_constructible']){
  1062.                 $infos_title[] = 'constructible';
  1063.             }
  1064.             if($this->getSurfTerrain() != "0"){
  1065.                 $infos_title[] = $this->getSurfTerrain() .' m²';
  1066.             }
  1067.         }
  1068.         //boutique -> activitescommerciales
  1069.         elseif(in_array($this->typebien, self::getTypes('commerces')) ){
  1070.             //1activitescommerciales, nature_activite, product_type_commercial
  1071.             $infos_title = [];
  1072.             $activitescommerciales = isset($feats['activitescommerciales']) ? $feats['activitescommerciales'] : '';
  1073.             if(!in_array($activitescommerciales,['','Autre activité'])){
  1074.                 $activitescommerciales = explode(',', $activitescommerciales);
  1075.                 $premiersTermes = array_slice($activitescommerciales, 0, 3);
  1076.                 $infos_title[] = implode(' - ', $premiersTermes);
  1077.             }
  1078.             elseif(isset($feats['nature_activite']) && $feats['nature_activite'] != ''){
  1079.                 $infos_title[]= $feats['nature_activite'];
  1080.             }
  1081.             elseif(isset($feats['product_type_commercial']) && $feats['product_type_commercial'] != ''){
  1082.                 $infos_title[] = $feats['product_type_commercial'];
  1083.             }
  1084.             else{
  1085.                 $infos_title[] = $this->getTypebien();
  1086.             }
  1087.             //Surface
  1088.             $not_surface = ['boutique'];
  1089.             if($this->getSurface() != "0" && !in_array($this->typebien, $not_surface) ){
  1090.                 $infos_title[]  = round($this->getSurface(),0, PHP_ROUND_HALF_DOWN) .' m²';
  1091.             }
  1092.         }
  1093.         else{
  1094.             if( $this->typebien == 'chateau' ){
  1095.                 if($feats['product_type_house'] != ''){
  1096.                     $infos_title = [$feats['product_type_house']];
  1097.                 }
  1098.             }
  1099.             //nombre de pièces
  1100.             $not_nb_piece = ['maison contemporaine', 'maison traditionelle'];
  1101.             if($this->getNbpieces() > 0 ) {
  1102.                 if(isset($feats['soustype_bien'])){
  1103.                     $infos_title[] = $this->getNbpieces() > 1 ? $this->getNbpieces() .' pièces' : $this->getNbpieces() .' pièce';
  1104.                 }
  1105.                 else{
  1106.                     $infos_title[] = $this->getNbpieces() > 1 ? $this->getNbpieces() .' pièces' : $this->getNbpieces() .' pièce';
  1107.                 }
  1108.                 
  1109.             }
  1110.             //Surface
  1111.             if($this->getSurface() != "0"){
  1112.                 $infos_title[]  = round($this->getSurface(),0, PHP_ROUND_HALF_DOWN) .' m²';
  1113.             }
  1114.         }
  1115.         return $infos_title ;
  1116.     }
  1117.     public function getLibelleCourt(): ?string
  1118.     {            
  1119.         $string = trim(strip_tags($this->getLibelle(), '<sup>'));
  1120.         $string = u( $string )->truncate(40, ' …', true);
  1121.         return $string;
  1122.     }
  1123.     public function getDescriptifCourt(): ?string
  1124.     {       
  1125.         $descriptif = $this->getDescriptif();
  1126.         $descriptif = preg_replace('#<br\s*/?>#i',' ',$descriptif);
  1127.         $string = trim(strip_tags($descriptif, '<sup>'));
  1128.         return u( $string )->truncate(135, ' …', false);
  1129.     }
  1130.     public function getIcone($key): ?string
  1131.     {   
  1132.         $icones = $this->getIcones();
  1133.         return $icones[$key];
  1134.     }
  1135.     
  1136.     public function getPublicFeatures(): ?array
  1137.     {   
  1138.         setlocale(LC_MONETARY, 'fr_FR');
  1139.         $values = [];
  1140.         $feats = $this->getFeatures();
  1141.         // $icones =  $this->getIcones();
  1142.         // statut
  1143.         // typebien
  1144.         // si_mandatexclusif
  1145.         // prix
  1146.         // surface
  1147.         // surf_terrain
  1148.         // nbpieces
  1149.         // nbchambres
  1150.         // $values['Statut'] = $this->getStatut();
  1151.         $values['Référence'] = $this->getRefannonce();
  1152.         // $values['Type de bien'] = $this->getTypebien();
  1153.         // $values['Prix'] = number_format( $this->getPrix(), 0, ',', ' ')." €";
  1154.         if($this->getNumeromandat() != "0"){
  1155.             $values['N° mandat'] = $this->getNumeromandat();
  1156.         }
  1157.         
  1158.         if($this->getSurface() != "0"){
  1159.             $values['Surface'] = $this->getSurface() .' m²';
  1160.         }
  1161.         // if($this->getSurfTerrain() != "0"){
  1162.         //     $values['Surface TERRAIN'] = $this->getSurfTerrain() .' m²';
  1163.         // }
  1164.         if($this->getNbpieces() != "0"){
  1165.             $values['Pièce(s)'] = $this->getNbpieces();
  1166.         }
  1167.         if($this->getNbchambres() != "0"){
  1168.             $values['Chambre(s)'] = $this->getNbchambres();
  1169.         } 
  1170.         if($this->getIcone('nbsdeau_sdb') > 0){
  1171.             $values["Salle de bain / Salle d'eau"] = $this->getIcone('nbsdeau_sdb');
  1172.         }
  1173.         if($this->getSurfTerrain() != "0" && $this->typebien !='terrain'){
  1174.             $values['Terrain'] = $this->getSurfTerrain() .' m²';
  1175.         }
  1176.         //contrainte sur l'affichage des honnoraires à la charge du vendeur 
  1177.         if( isset($feats['honoraires_charges_de']) && stripos($feats['honoraires_charges_de'], 'vendeur') !== false ){
  1178.             if( isset($feats['honoraires']) ){
  1179.                 unset($feats['honoraires']);
  1180.             }
  1181.             if( isset($feats['prix_hors_honoraires']) ){
  1182.                 unset($feats['prix_hors_honoraires']);
  1183.             }        
  1184.         }
  1185.         if(in_array($this->typebien, ['boutique', 'terrain']) ){
  1186.             unset($feats['typecuisine']);
  1187.         }
  1188.         // if($this->getCa() > 0 && (int) $feats['annee_reference_ca'] > 0 ){
  1189.         //     $feats['ca'] = $this->getCa();
  1190.         // }
  1191.         // if($this->getEbe() > 0 && (int) $feats['annee_reference_ebe'] > 0){
  1192.         //     $feats['ebe'] = $this->getEbe();
  1193.         // }
  1194.         if(isset($feats['surface_sol']) &&  $values['Surface'] == $feats['surface_sol'] ){
  1195.             unset($feats['surface_sol']);
  1196.         }
  1197.         if($this->getCa() > 0 ){
  1198.             $feats['ca'] = $this->getCa();
  1199.         }
  1200.         if($this->getEbe() > 0 ){
  1201.             $feats['ebe'] = $this->getEbe();
  1202.         }
  1203.         if(isset($feats['ca_n_1']) && $feats['ca_n_1'] > 0 ){
  1204.             // unset($feats['ca']);
  1205.         }
  1206.         if(isset($feats['ebe_reconstituted']) && $feats['ebe_reconstituted'] > 0 ){
  1207.             unset($feats['ebe']);
  1208.         }
  1209.         $labels = [
  1210.         'statut' => 'Statut',
  1211.         'numeromandat' => 'N° mandat',
  1212.         'surface' => 'Surface',
  1213.         'surface_sol' => 'Surface au sol',
  1214.         'pieces' => 'Pièce(s)',
  1215.         'nbchambres' => 'Chambre(s)',
  1216.         'nbsdeau_sdb' => "Salle de bain / Salle d'eau",
  1217.         'typechauffage' => 'Chauffage',
  1218.         'typecuisine' => 'Cuisine',
  1219.         'fenetres' => "Fenêtres",
  1220.         'assainissement' => 'Assainissement',
  1221.         'annee_construction' => 'Année de construction',
  1222.         'etage' => 'Étage',
  1223.         'orientation' => 'Orientation',
  1224.         'terrain' => 'Terrain',        
  1225.         'si_constructible' => 'Terrain constructible',
  1226.         'si_viabilise' => 'Terrain viabilisé',
  1227.         'date_dispo' => 'Date de disponibilité',
  1228.         'loyer_annuel_global' => 'Loyer annuel',
  1229.         // 'loyer_annuel_metre' => 'Loyer au m²', //euro
  1230.         // 'charges_annuelles_globales' => 'Charges annuelles',
  1231.         'charges' => 'Charges', //euro
  1232.         'charges_annuelles' => 'Charges annuelles', //euro
  1233.         'fermeture_hebdomadaire' => 'Fermeture', //?? non present
  1234.         'horaires' => 'Horaires',
  1235.         'si_logement_de_fonction' => 'Logement de fonction',
  1236.         'si_copropriete' => 'Copropriété',
  1237.         'nombre_lots' => 'Nombre de lots',
  1238.         'si_syndic_procedure' => 'Procédure syndicat',
  1239.         'detail_syndic_procedure' => 'Détail procédure',
  1240.         // 'ca' => 'CA ' . $feats['annee_reference_ca'] ,
  1241.         // 'ebe' => 'EBE '. $feats['annee_reference_ebe'], 
  1242.         'ca' => 'CA',
  1243.         // 'ca_n_1' => 'CA n-1',
  1244.         'ebe' => 'EBE',
  1245.         'ebe_reconstituted' => 'EBE retraité' ,
  1246.         'prix_hors_honoraires' => 'Prix hors honoraires', //euro
  1247.         'honoraires' => 'Honoraires', //euro
  1248.         'honoraires_charges_de' => 'Honoraires charge',
  1249.         ];
  1250.         $suffix['surface'] = ' m²';
  1251.         $suffix['surface_sol'] = ' m²';
  1252.         $suffix['surf_terrain'] = ' m²';
  1253.         $suffix['charges'] = ' €';
  1254.         $suffix['charges_annuelles'] = ' €';
  1255.         $suffix['prix_hors_honoraires'] = ' €';
  1256.         $suffix['loyer_annuel_global'] = ' €';
  1257.         $suffix['ca'] = ' €';
  1258.         $suffix['ebe'] = ' €';
  1259.         $suffix['ebe_reconstituted'] = ' €';
  1260.         $suffix['honoraires'] = '%';
  1261.         foreach ($feats as $key => $value) { 
  1262.             if(isset($labels[$key]) && $value!="" && $value!= "0" ){
  1263.                 $suf = isset($suffix[$key]) ? $suffix[$key] : '';
  1264.                 if(is_bool($value)){
  1265.                         $value = $value ? 'Oui': 'Non';
  1266.                 }
  1267.                 if( $suf  == ' €'){
  1268.                     $value = number_format( (float) $value, 0, ',', '.');
  1269.                 }
  1270.                 if( $suf  == '%'){
  1271.                     // $value = round( (float) $value, 1);
  1272.                     $value = number_format( (float) $value, 1, ',', ' ');
  1273.                 }
  1274.                 if($key  == 'date_dispo'){
  1275.                     // $value = "24/02/2021";
  1276.                     $date_dispo = \DateTime::createFromFormat('d/m/Y', $value);
  1277.                     $now = new \DateTime();
  1278.                     $nb_day_diff = (int) $now->diff($date_dispo)->format('%R%a');
  1279.                     $value = $nb_day_diff <= 0 ? "Immédiate" : $value;
  1280.                 }
  1281.                 $values[$labels[$key]] = $value.$suf;
  1282.             }
  1283.         }
  1284.         //TRI SELON L'ordre des labels
  1285.         $order = array_values ($labels);    
  1286.         uksort($values, function($key1, $key2) use ($order) {
  1287.             return ((array_search($key1, $order) > array_search($key2, $order)) ? 1 : -1);
  1288.         });
  1289.         return $values;
  1290.     }
  1291.     public function getPublicIcones(): ?array
  1292.     {   
  1293.         $inflector = new FrenchInflector();
  1294.         $icones = [];
  1295.         // $values['m2_surface'] = $this->getSurface() ;
  1296.         // $values['m2_surf_terrain'] = $this->getSurfTerrain();
  1297.         // $values['nbpieces'] = $this->getNbpieces();
  1298.         // $values['nbchambres'] = $this->getNbchambres();
  1299.         $labels = [
  1300.         // 'm2_surface' => "Surface",
  1301.         // 'm2_surf_terrain' => "Terrain",
  1302.         // 'nbpieces' => "Pièce",
  1303.         // 'nbchambres' => "Chambre",
  1304.         // 'nbsdb' => "Salle de bain",
  1305.         // 'nbsdeau' => "Salle d'eau",
  1306.         // 'nbsdeau_sdb' => "Salle d'eau",
  1307.         'si_piscine' => "Piscine",
  1308.         'si_terrasse' => "Terrasse",
  1309.         'si_cheminee' => "Cheminée",
  1310.         'nbboxes' => "Garage",
  1311.         'nbparkings' => "Parking",
  1312.         'si_cave' => "Cave",
  1313.         'si_ascenseur' => "Ascenceur",
  1314.         'si_digicode' => "Digicode",
  1315.         'si_interphone' => "Interphone",
  1316.         'si_gardien' => "Gardien",
  1317.         'si_alarme' => "Alarme",
  1318.         'si_cabletv' => "Cable TV",
  1319.         'si_climatisation' => "Climatisation",
  1320.         'si_amgnthandicapes' => "PMR",
  1321.         'si_constructible' => 'Terrain constructible',
  1322.         'si_viabilise' => 'Terrain viabilisé',
  1323.         'si_sous_sol' => 'Sous sol'
  1324.         ];
  1325.         // $icones = array_merge( $values, $this->getIcones() );
  1326.         foreach ( $this->getIcones() as $key => $val) {  
  1327.             $value  = false;
  1328.             if(isset($labels[$key])){
  1329.                 if(preg_match('#^si_.+#' , $key , $match) && $val == true){ //Boolean
  1330.                     $value = $labels[$key];
  1331.                 }
  1332.                 elseif(preg_match('#^nb.+#' , $key , $match) && $val != "" && (int)$val > 0){ //Integer
  1333.                     $label = $labels[$key];
  1334.                     $label  = (int)$val > 1 && !preg_match('#^Salle.+#', $label ) ? $inflector->pluralize( $label )[0] : $label; 
  1335.                     $label  = (int)$val > 1 && preg_match('#^Salle.+#', $label ) ? preg_replace('#^Salle(.+)#', 'Salles$1', $label) : $label; 
  1336.                     $value = $val ." ". $label; 
  1337.                 }
  1338.                 elseif(preg_match('#^m2_.+#' , $key , $match) && (int)$val > 0){ //Surface
  1339.                     $value = $labels[$key] . " ".$val;
  1340.                 }
  1341.                 
  1342.                 if($value != false){
  1343.                     $suffix = isset($suffix[$key]) ? $suffix[$key] : '';
  1344.                     $icones[$key] = $value.$suffix;
  1345.                 }
  1346.             }
  1347.         }
  1348.         if(isset($icones['si_cave']) && isset($icones['si_sous_sol']) ){
  1349.             unset($icones['si_sous_sol']);
  1350.         }
  1351.         //TRI SELON L'ordre des labels
  1352.         $order = array_keys($labels);    
  1353.         uksort($icones, function($key1, $key2) use ($order) {
  1354.             return ((array_search($key1, $order) > array_search($key2, $order)) ? 1 : -1);
  1355.         });
  1356.         return $icones;
  1357.     }
  1358.     public function getPecLetters(): ?array
  1359.     {
  1360.         $pecLetters = [];
  1361.         $feats = $this->getFeatures();
  1362.         $letters = array_flip(range('A', 'G'));
  1363.         if(isset($feats['bilanconsoenergie']) && isset($letters[$feats['bilanconsoenergie']])  && isset($letters[$feats['bilanemissionges']]) ){
  1364.             // DPE (D) >= GES (B) : D,B
  1365.             if( $letters[$feats['bilanconsoenergie']] >= $letters[$feats['bilanemissionges']]){
  1366.                 $pecLetters = ['dpe' => $feats['bilanconsoenergie'], 'gse' => $feats['bilanemissionges']];
  1367.             }
  1368.             //DPE (B) > GES (G)  : G,G
  1369.             else{
  1370.                 $pecLetters = ['dpe' => $feats['bilanemissionges'], 'gse' => $feats['bilanemissionges']];
  1371.             }
  1372.             if( in_array($pecLetters['dpe'] ,['F', 'G']) ){
  1373.                 // dump($this->getRefannonce());
  1374.                 $pecLetters['label'] = "Passoire energétique";
  1375.             }
  1376.             
  1377.             // $pecLetters['dpe'] = 'G';
  1378.         }
  1379.         return $pecLetters;
  1380.     }
  1381.     public function getSiNuPropriete(): ?bool
  1382.     {                       
  1383.         $patterns = [
  1384.             'NUE-PROPRIÉTÉ',
  1385.             'NUE-PROPRIETE',
  1386.         ];
  1387.         return preg_match('#^(.+)'.implode('|', $patterns).'(.+)$#miu' , $this->descriptif , $match)  ? true : false;
  1388.     }
  1389.     
  1390.     /**
  1391.      * @return Collection|User[]
  1392.      */
  1393.     public function getUsers(): Collection
  1394.     {
  1395.         return $this->users;
  1396.     }
  1397.     public function addUser(User $user): self
  1398.     {
  1399.         if (!$this->users->contains($user)) {
  1400.             $this->users[] = $user;
  1401.             $user->addFavorite($this);
  1402.         }
  1403.         return $this;
  1404.     }
  1405.     public function removeUser(User $user): self
  1406.     {
  1407.         if ($this->users->removeElement($user)) {
  1408.             $user->removeFavorite($this);
  1409.         }
  1410.         return $this;
  1411.     }
  1412.     public static function createRange($numbers){
  1413.         sort($numbers);
  1414.         $min = min($numbers);
  1415.         $max = max($numbers);
  1416.         $seuils = [$min]; 
  1417.         while(end($seuils) * 2 < $max){
  1418.             $seuil = end($seuils) * 2;
  1419.             $seuils[] = end($seuils) * 2;
  1420.         }
  1421.         $seuils[] = $max;
  1422.         //arrondi
  1423.         $rangeLimits =[];
  1424.         foreach($seuils as $index => $seuil){
  1425.             $nbdigit = mb_strlen($seuil) ;
  1426.             $unit = substr($seuil, 0,1);
  1427.             $diviseur = 1;
  1428.             for($i=1; $i< $nbdigit; $i++){
  1429.                 $diviseur = $diviseur * 10;
  1430.             }
  1431.             $decimal = $seuil/$diviseur;
  1432.             if($seuil == $min){
  1433.                 $decimal_round =  floor($decimal*10)/10;
  1434.             }
  1435.             elseif($seuil == $max){
  1436.                 $decimal_round =  ceil($decimal*10)/10;
  1437.             }
  1438.             else{
  1439.                 $decimal_round =  round($decimal, 1);
  1440.             }
  1441.             $round = $decimal_round * $diviseur;
  1442.             $rangeLimits[] = (int) number_format($round,0, '','');
  1443.         }
  1444.         $ranges = array();
  1445.         for($i = 0; $i < count($rangeLimits); $i++){
  1446.             if($i == count($rangeLimits)-1){
  1447.                 break;
  1448.             }
  1449.             $lowLimit = $rangeLimits[$i];
  1450.             $highLimit = $rangeLimits[$i+1];
  1451.             $ranges[$i]['ranges']['min'] = $lowLimit;
  1452.             $ranges[$i]['ranges']['max'] = $highLimit;
  1453.             $ranges[$i]['values'] =  []; 
  1454.             
  1455.             foreach($numbers as $number){
  1456.                 if($number >= $lowLimit && $number <= $highLimit){
  1457.                     $ranges[$i]['values'][] = $number;
  1458.                 }
  1459.             }
  1460.         }
  1461.         return $ranges;
  1462.     }
  1463.     public function getSousType(): ?SousType
  1464.     {
  1465.         return $this->sous_type;
  1466.     }
  1467.     public function setSousType(?SousType $sous_type): self
  1468.     {
  1469.         $this->sous_type = $sous_type;
  1470.         return $this;
  1471.     }
  1472.     public function getCa(): ?float
  1473.     {
  1474.         return $this->ca;
  1475.     }
  1476.     public function setCa(?float $ca): self
  1477.     {
  1478.         $this->ca = $ca;
  1479.         return $this;
  1480.     }
  1481.     public function getEbe(): ?float
  1482.     {
  1483.         return $this->ebe;
  1484.     }
  1485.     public function setEbe(?float $ebe): self
  1486.     {
  1487.         $this->ebe = $ebe;
  1488.         return $this;
  1489.     }
  1490.     public function isSiMandatexclusif(): ?bool
  1491.     {
  1492.         return $this->si_mandatexclusif;
  1493.     }
  1494.     public function isIsNewChecked(): ?bool
  1495.     {
  1496.         return $this->is_new_checked;
  1497.     }
  1498.     public function isIsDeleteChecked(): ?bool
  1499.     {
  1500.         return $this->is_delete_checked;
  1501.     }
  1502.     /**
  1503.      * @return Collection<int, SearchNotification>
  1504.      */
  1505.     public function getNotifications(): Collection
  1506.     {
  1507.         return $this->notifications;
  1508.     }
  1509.     public function addNotification(SearchNotification $notification): self
  1510.     {
  1511.         if (!$this->notifications->contains($notification)) {
  1512.             $this->notifications[] = $notification;
  1513.             $notification->addEstate($this);
  1514.         }
  1515.         return $this;
  1516.     }
  1517.     public function removeNotification(SearchNotification $notification): self
  1518.     {
  1519.         if ($this->notifications->removeElement($notification)) {
  1520.             $notification->removeEstate($this);
  1521.         }
  1522.         return $this;
  1523.     }
  1524.     /**
  1525.      * @return Collection<int, Agent>
  1526.      */
  1527.     public function getShareWithAgents(): Collection
  1528.     {
  1529.         return $this->share_with_agents;
  1530.     }
  1531.     public function setShareWithAgents(iterable $agents): self
  1532.     {
  1533.         foreach ($this->share_with_agents as $agent) {
  1534.             $this->removeShareWithAgent($agent);
  1535.         }
  1536.         foreach ($agents as $agent) {
  1537.             $this->addShareWithAgent($agent);
  1538.         }
  1539.         return $this;
  1540.     }
  1541.     public function addShareWithAgent(Agent $shareWithAgent): self
  1542.     {
  1543.         if (!$this->share_with_agents->contains($shareWithAgent)) {
  1544.             $this->share_with_agents[] = $shareWithAgent;
  1545.         }
  1546.         return $this;
  1547.     }
  1548.     public function removeShareWithAgent(Agent $shareWithAgent): self
  1549.     {
  1550.         $this->share_with_agents->removeElement($shareWithAgent);
  1551.         return $this;
  1552.     }
  1553. }