1<?php 2 3declare(strict_types=1); 4 5namespace JMS\Serializer\Exclusion; 6 7use JMS\Serializer\Context; 8use JMS\Serializer\Exception\RuntimeException; 9use JMS\Serializer\Metadata\ClassMetadata; 10use JMS\Serializer\Metadata\PropertyMetadata; 11 12final class GroupsExclusionStrategy implements ExclusionStrategyInterface 13{ 14 public const DEFAULT_GROUP = 'Default'; 15 16 /** 17 * @var array 18 */ 19 private $groups = []; 20 21 /** 22 * @var bool 23 */ 24 private $nestedGroups = false; 25 26 public function __construct(array $groups) 27 { 28 if (empty($groups)) { 29 $groups = [self::DEFAULT_GROUP]; 30 } 31 32 foreach ($groups as $group) { 33 if (is_array($group)) { 34 $this->nestedGroups = true; 35 break; 36 } 37 } 38 39 if ($this->nestedGroups) { 40 $this->groups = $groups; 41 } else { 42 foreach ($groups as $group) { 43 $this->groups[$group] = true; 44 } 45 } 46 } 47 48 /** 49 * {@inheritDoc} 50 */ 51 public function shouldSkipClass(ClassMetadata $metadata, Context $navigatorContext): bool 52 { 53 return false; 54 } 55 56 /** 57 * {@inheritDoc} 58 */ 59 public function shouldSkipProperty(PropertyMetadata $property, Context $navigatorContext): bool 60 { 61 if ($this->nestedGroups) { 62 $groups = $this->getGroupsFor($navigatorContext); 63 64 if (!$property->groups) { 65 return !in_array(self::DEFAULT_GROUP, $groups); 66 } 67 68 return $this->shouldSkipUsingGroups($property, $groups); 69 } else { 70 if (!$property->groups) { 71 return !isset($this->groups[self::DEFAULT_GROUP]); 72 } 73 74 foreach ($property->groups as $group) { 75 if (isset($this->groups[$group])) { 76 return false; 77 } 78 } 79 return true; 80 } 81 } 82 83 private function shouldSkipUsingGroups(PropertyMetadata $property, array $groups): bool 84 { 85 foreach ($property->groups as $group) { 86 if (in_array($group, $groups)) { 87 return false; 88 } 89 } 90 91 return true; 92 } 93 94 private function getGroupsFor(Context $navigatorContext): array 95 { 96 $paths = $navigatorContext->getCurrentPath(); 97 98 $groups = $this->groups; 99 foreach ($paths as $index => $path) { 100 if (!array_key_exists($path, $groups)) { 101 break; 102 } 103 104 if (!is_array($groups[$path])) { 105 throw new RuntimeException(sprintf('The group value for the property path "%s" should be an array, "%s" given', $index, gettype($groups[$path]))); 106 } 107 108 $groups = $groups[$path]; 109 } 110 111 return $groups; 112 } 113} 114