src/App/Model/Query/ConditionQuery/ConditionConfig.php line 415

Open in your IDE?
  1. <?php
  2. namespace App\Model\Query\ConditionQuery;
  3. use App\Util\Arrays;
  4. use JsonSerializable;
  5. /**
  6.  * Top level object that contains all the filters that are defined for a customer.
  7.  * This could have been stored simplay as just an array with no need for this class.
  8.  * However, it is expected that there may be more properties needed in the future.
  9.  *
  10.  * @see https://coda.io/d/_diyKeRjYYS-/Flexible-Messaging-Prototype_suNzV#_luVi2
  11.  */
  12. final class ConditionConfig implements JsonSerializable
  13. {
  14.     /**
  15.      * The various filtering options that are defined in this configuration.
  16.      *
  17.      * @var array<ConditionSchema>
  18.      */
  19.     protected array $schemas = [];
  20.     /**
  21.      * Any key/value lookups that certain filters may reference in their schema.
  22.      *
  23.      * @var array<ConditionDictionary>
  24.      */
  25.     protected array $dictionaries = [];
  26.     /**
  27.      * @var array<ConditionLookup>
  28.      */
  29.     protected array $lookups = [];
  30.     /**
  31.      * @param array<ConditionSchema> $schemas
  32.      * @param array<ConditionDictionary> $dictionaries
  33.      * @param array<ConditionLookup> $lookups
  34.      */
  35.     public function __construct(
  36.         array $schemas = [],
  37.         array $dictionaries = [],
  38.         array $lookups = []
  39.     )
  40.     {
  41.         $this
  42.             ->setSchemas($schemas)
  43.             ->setDictionaries($dictionaries)
  44.             ->setLookups($lookups);
  45.     }
  46.     /**
  47.      * @param ConditionConfig $config
  48.      * @return $this
  49.      */
  50.     public function merge(ConditionConfig $config): self
  51.     {
  52.         foreach ($config->getSchemas() as $schema) {
  53.             if ( ! $this->hasSchema($schema->getFilter())) {
  54.                 $this->addSchema(clone $schema);
  55.             }
  56.         }
  57.         foreach ($config->getDictionaries() as $dictionary) {
  58.             if ( ! $this->hasDictionary($dictionary->getName())) {
  59.                 $this->addDictionary(clone $dictionary);
  60.             }
  61.         }
  62.         foreach ($config->getLookups() as $lookup) {
  63.             if ( ! $this->hasLookup($lookup->getName())) {
  64.                 $this->addLookup(clone $lookup);
  65.             }
  66.         }
  67.         return $this;
  68.     }
  69.     /**
  70.      * @return array<ConditionSchema>
  71.      */
  72.     public function getSchemas(): array
  73.     {
  74.         return $this->schemas;
  75.     }
  76.     /**
  77.      * @param array<ConditionSchema> $schemas
  78.      * @return $this
  79.      */
  80.     public function setSchemas(array $schemas): self
  81.     {
  82.         $this->schemas = [];
  83.         foreach ($schemas as $schema) {
  84.             $this->addSchema($schemafalse);
  85.         }
  86.         $this->sortSchemas();
  87.         return $this;
  88.     }
  89.     /**
  90.      * @param string $filter
  91.      * @return bool
  92.      */
  93.     public function hasSchema(string $filter): bool
  94.     {
  95.         return array_key_exists($filter$this->getSchemas());
  96.     }
  97.     /**
  98.      * @param string $filter
  99.      * @return ConditionSchema|null
  100.      */
  101.     public function getSchema(string $filter): ?ConditionSchema
  102.     {
  103.         if ( ! $this->hasSchema($filter)) {
  104.             return null;
  105.         }
  106.         return $this->getSchemas()[$filter];
  107.     }
  108.     /**
  109.      * Given a new filter, will attempt to add it to the set.
  110.      * Filters should not be added more than once.
  111.      *
  112.      * @param ConditionSchema $new
  113.      * @param bool $sort
  114.      * @return $this
  115.      */
  116.     public function addSchema(
  117.         ConditionSchema $new,
  118.         bool $sort true
  119.     ): self
  120.     {
  121.         // do not add if we alread have the same filter; no matter if this is a new object or not
  122.         if ($this->hasSchema($new->getFilter())) {
  123.             throw new \LogicException(sprintf(
  124.                 'Schema "%s" has already been added to the collection.',
  125.                 $new->getFilter()
  126.             ));
  127.         }
  128.         // attach the schema to the collection
  129.         $this->schemas[$new->getFilter()] = $new;
  130.         // set the parent on the schema to us
  131.         $new->setConditionConfig($this);
  132.         // sort if we are flagged to do that
  133.         if ($sort) {
  134.             $this->sortSchemas();
  135.         }
  136.         return $this;
  137.     }
  138.     /**
  139.      * Helper function to sort the schemas in the filters.
  140.      * Sorting is done by the human-friendly name.
  141.      *
  142.      * @return void
  143.      */
  144.     protected function sortSchemas(): void
  145.     {
  146.         uasort(
  147.             $this->schemas,
  148.             static function (ConditionSchema $aConditionSchema $b) {
  149.                 if (($result strcasecmp($a->getCategory(), $b->getCategory())) !== 0) {
  150.                     return $result;
  151.                 }
  152.                 return strcasecmp($a->getName(), $b->getName());
  153.             }
  154.         );
  155.     }
  156.     /**
  157.      * @return array<ConditionDictionary>
  158.      */
  159.     public function getDictionaries(): array
  160.     {
  161.         return $this->dictionaries;
  162.     }
  163.     /**
  164.      * @param array<ConditionDictionary> $dictionaries
  165.      * @return $this
  166.      */
  167.     public function setDictionaries(array $dictionaries): self
  168.     {
  169.         $this->dictionaries = [];
  170.         foreach ($dictionaries as $dictionary) {
  171.             $this->addDictionary($dictionaryfalse);
  172.         }
  173.         $this->sortDictionaries();
  174.         return $this;
  175.     }
  176.     /**
  177.      * @param string $name
  178.      * @return bool
  179.      */
  180.     public function hasDictionary(string $name): bool
  181.     {
  182.         return array_key_exists($name$this->getDictionaries());
  183.     }
  184.     /**
  185.      * @param string $name
  186.      * @return ConditionDictionary|null
  187.      */
  188.     public function getDictionary(string $name): ?ConditionDictionary
  189.     {
  190.         if ( ! $this->hasDictionary($name)) {
  191.             return null;
  192.         }
  193.         return $this->getDictionaries()[$name];
  194.     }
  195.     /**
  196.      * Given a new dictionary, will attempt to add it to the set.
  197.      * Dictionaries should not be added more than once.
  198.      *
  199.      * @param ConditionDictionary $new
  200.      * @param bool $sort
  201.      * @return $this
  202.      */
  203.     public function addDictionary(
  204.         ConditionDictionary $new,
  205.         bool $sort true
  206.     ): self
  207.     {
  208.         // see if we have already been added based on our name
  209.         if ($this->hasDictionary($new->getName())) {
  210.             throw new \LogicException(sprintf(
  211.                 'Dictionary "%s" has already been added to the collection.',
  212.                 $new->getName()
  213.             ));
  214.         }
  215.         // add to collection
  216.         $this->dictionaries[$new->getName()] = $new;
  217.         // set its parent to us
  218.         $new->setConditionConfig($this);
  219.         // handle sorting
  220.         if ($sort) {
  221.             $this->sortDictionaries();
  222.         }
  223.         return $this;
  224.     }
  225.     /**
  226.      * Helper function to sort the schemas in the filters.
  227.      * Sorting is done by the human-friendly name.
  228.      *
  229.      * @return void
  230.      */
  231.     protected function sortDictionaries(): void
  232.     {
  233.         uasort(
  234.             $this->dictionaries,
  235.             static function (ConditionDictionary $aConditionDictionary $b) {
  236.                 return strcasecmp($a->getName(), $b->getName());
  237.             }
  238.         );
  239.     }
  240.     /**
  241.      * @return array<ConditionLookup>
  242.      */
  243.     public function getLookups(): array
  244.     {
  245.         return $this->lookups;
  246.     }
  247.     /**
  248.      * @param array<ConditionLookup> $lookups
  249.      * @return $this
  250.      */
  251.     public function setLookups(array $lookups): self
  252.     {
  253.         $this->lookups = [];
  254.         foreach ($lookups as $lookup) {
  255.             $this->addLookup($lookupfalse);
  256.         }
  257.         $this->sortLookups();
  258.         return $this;
  259.     }
  260.     /**
  261.      * @param string $name
  262.      * @return bool
  263.      */
  264.     public function hasLookup(string $name): bool
  265.     {
  266.         return array_key_exists($name$this->getLookups());
  267.     }
  268.     /**
  269.      * @param string $name
  270.      * @return ConditionLookup|null
  271.      */
  272.     public function getLookup(string $name): ?ConditionLookup
  273.     {
  274.         if ( ! $this->hasLookup($name)) {
  275.             return null;
  276.         }
  277.         return $this->getLookups()[$name];
  278.     }
  279.     /**
  280.      * Given a new dictionary, will attempt to add it to the set.
  281.      * Dictionaries should not be added more than once.
  282.      *
  283.      * @param ConditionLookup $new
  284.      * @param bool $sort
  285.      * @return $this
  286.      */
  287.     public function addLookup(
  288.         ConditionLookup $new,
  289.         bool $sort true
  290.     ): self
  291.     {
  292.         // see if we have already been added based on our name
  293.         if ($this->hasLookup($new->getName())) {
  294.             throw new \LogicException(sprintf(
  295.                 'Lookup "%s" has already been added to the collection.',
  296.                 $new->getName()
  297.             ));
  298.         }
  299.         // add to collection
  300.         $this->lookups[$new->getName()] = $new;
  301.         // set its parent to us
  302.         $new->setConditionConfig($this);
  303.         // handle sorting
  304.         if ($sort) {
  305.             $this->sortLookups();
  306.         }
  307.         return $this;
  308.     }
  309.     /**
  310.      * @return void
  311.      */
  312.     protected function sortLookups(): void
  313.     {
  314.         uasort(
  315.             $this->lookups,
  316.             static function (ConditionLookup $aConditionLookup $b) {
  317.                 return strcasecmp($a->getName(), $b->getName());
  318.             }
  319.         );
  320.     }
  321.     /**
  322.      * {@inheritDoc}
  323.      */
  324.     public function jsonSerialize(): array
  325.     {
  326.         return [
  327.             'schemas' => array_map(
  328.                 static function (array $schema) {
  329.                     unset($schema['filter']);
  330.                     return $schema;
  331.                 },
  332.                 Arrays::mapObjectMethods($this->getSchemas(), 'jsonSerialize'),
  333.             ),
  334.             'dictionaries' => array_map(
  335.                 static function (array $dictionary) {
  336.                     return $dictionary['glossary'];
  337.                 },
  338.                 Arrays::mapObjectMethods($this->getDictionaries(), 'jsonSerialize'),
  339.             ),
  340.             'lookups' => array_map(
  341.                 static function (array $lookup) {
  342.                     return $lookup['filters'];
  343.                 },
  344.                 Arrays::mapObjectMethods($this->getLookups(), 'jsonSerialize'),
  345.             ),
  346.         ];
  347.     }
  348.     /**
  349.      * @param array $serialized
  350.      * @return $this
  351.      */
  352.     public function jsonUnserialize(array $serialized): self
  353.     {
  354.         return $this
  355.             ->setSchemas(
  356.                 array_map(
  357.                     static function ($index) use ($serialized) {
  358.                         // TODO: done this way for legacy config that uses numerical indexed vs filter as key
  359.                         switch (true) {
  360.                             // old way
  361.                             case is_int($index):
  362.                                 $schema $serialized['schemas'][$index];
  363.                                 break;
  364.                             // new way
  365.                             case is_string($index):
  366.                                 $schema array_merge(
  367.                                     $serialized['schemas'][$index],
  368.                                     [
  369.                                         'filter' => $index,
  370.                                     ],
  371.                                 );
  372.                                 break;
  373.                             default:
  374.                                 throw new \LogicException();
  375.                         }
  376.                         return ConditionSchema::factory($schema);
  377.                     },
  378.                     array_keys($serialized['schemas'] ?? []),
  379.                 ),
  380.             )
  381.             ->setDictionaries(
  382.                 array_map(
  383.                     static function (string $name) use ($serialized) {
  384.                         return ConditionDictionary::factory([
  385.                             'name' => $name,
  386.                             'glossary' => $serialized['dictionaries'][$name],
  387.                         ]);
  388.                     },
  389.                     array_keys($serialized['dictionaries'] ?? []),
  390.                 ),
  391.             )
  392.             ->setLookups(
  393.                 array_map(
  394.                     static function (string $name) use ($serialized) {
  395.                         return ConditionLookup::factory([
  396.                             'name' => $name,
  397.                             'filters' => $serialized['lookups'][$name],
  398.                         ]);
  399.                     },
  400.                     array_keys($serialized['lookups'] ?? []),
  401.                 ),
  402.             );
  403.     }
  404.     /**
  405.      * @param array $serialized
  406.      * @return ConditionConfig
  407.      */
  408.     public static function factory(array $serialized): ConditionConfig
  409.     {
  410.         return (new ConditionConfig())->jsonUnserialize($serialized);
  411.     }
  412. }