1<?php 2 3/* 4 * This file is part of the Symfony package. 5 * 6 * (c) Fabien Potencier <fabien@symfony.com> 7 * 8 * For the full copyright and license information, please view the LICENSE 9 * file that was distributed with this source code. 10 */ 11 12namespace Symfony\Component\Validator\Mapping; 13 14use Symfony\Component\Validator\Constraint; 15use Symfony\Component\Validator\Constraints\Composite; 16use Symfony\Component\Validator\Exception\ConstraintDefinitionException; 17 18/** 19 * Stores all metadata needed for validating a class property. 20 * 21 * The method of accessing the property's value must be specified by subclasses 22 * by implementing the {@link newReflectionMember()} method. 23 * 24 * This class supports serialization and cloning. 25 * 26 * @author Bernhard Schussek <bschussek@gmail.com> 27 * 28 * @see PropertyMetadataInterface 29 */ 30abstract class MemberMetadata extends GenericMetadata implements PropertyMetadataInterface 31{ 32 /** 33 * @internal This property is public in order to reduce the size of the 34 * class' serialized representation. Do not access it. Use 35 * {@link getClassName()} instead. 36 */ 37 public $class; 38 39 /** 40 * @internal This property is public in order to reduce the size of the 41 * class' serialized representation. Do not access it. Use 42 * {@link getName()} instead. 43 */ 44 public $name; 45 46 /** 47 * @internal This property is public in order to reduce the size of the 48 * class' serialized representation. Do not access it. Use 49 * {@link getPropertyName()} instead. 50 */ 51 public $property; 52 53 /** 54 * @var \ReflectionMethod[]|\ReflectionProperty[] 55 */ 56 private $reflMember = []; 57 58 /** 59 * @param string $class The name of the class this member is defined on 60 * @param string $name The name of the member 61 * @param string $property The property the member belongs to 62 */ 63 public function __construct(string $class, string $name, string $property) 64 { 65 $this->class = $class; 66 $this->name = $name; 67 $this->property = $property; 68 } 69 70 /** 71 * {@inheritdoc} 72 */ 73 public function addConstraint(Constraint $constraint) 74 { 75 $this->checkConstraint($constraint); 76 77 parent::addConstraint($constraint); 78 79 return $this; 80 } 81 82 /** 83 * {@inheritdoc} 84 */ 85 public function __sleep() 86 { 87 return array_merge(parent::__sleep(), [ 88 'class', 89 'name', 90 'property', 91 ]); 92 } 93 94 /** 95 * Returns the name of the member. 96 * 97 * @return string 98 */ 99 public function getName() 100 { 101 return $this->name; 102 } 103 104 /** 105 * {@inheritdoc} 106 */ 107 public function getClassName() 108 { 109 return $this->class; 110 } 111 112 /** 113 * {@inheritdoc} 114 */ 115 public function getPropertyName() 116 { 117 return $this->property; 118 } 119 120 /** 121 * Returns whether this member is public. 122 * 123 * @param object|string $objectOrClassName The object or the class name 124 * 125 * @return bool 126 */ 127 public function isPublic($objectOrClassName) 128 { 129 return $this->getReflectionMember($objectOrClassName)->isPublic(); 130 } 131 132 /** 133 * Returns whether this member is protected. 134 * 135 * @param object|string $objectOrClassName The object or the class name 136 * 137 * @return bool 138 */ 139 public function isProtected($objectOrClassName) 140 { 141 return $this->getReflectionMember($objectOrClassName)->isProtected(); 142 } 143 144 /** 145 * Returns whether this member is private. 146 * 147 * @param object|string $objectOrClassName The object or the class name 148 * 149 * @return bool 150 */ 151 public function isPrivate($objectOrClassName) 152 { 153 return $this->getReflectionMember($objectOrClassName)->isPrivate(); 154 } 155 156 /** 157 * Returns the reflection instance for accessing the member's value. 158 * 159 * @param object|string $objectOrClassName The object or the class name 160 * 161 * @return \ReflectionMethod|\ReflectionProperty The reflection instance 162 */ 163 public function getReflectionMember($objectOrClassName) 164 { 165 $className = \is_string($objectOrClassName) ? $objectOrClassName : \get_class($objectOrClassName); 166 if (!isset($this->reflMember[$className])) { 167 $this->reflMember[$className] = $this->newReflectionMember($objectOrClassName); 168 } 169 170 return $this->reflMember[$className]; 171 } 172 173 /** 174 * Creates a new reflection instance for accessing the member's value. 175 * 176 * Must be implemented by subclasses. 177 * 178 * @param object|string $objectOrClassName The object or the class name 179 * 180 * @return \ReflectionMethod|\ReflectionProperty The reflection instance 181 */ 182 abstract protected function newReflectionMember($objectOrClassName); 183 184 private function checkConstraint(Constraint $constraint) 185 { 186 if (!\in_array(Constraint::PROPERTY_CONSTRAINT, (array) $constraint->getTargets(), true)) { 187 throw new ConstraintDefinitionException(sprintf('The constraint "%s" cannot be put on properties or getters.', \get_class($constraint))); 188 } 189 190 if ($constraint instanceof Composite) { 191 foreach ($constraint->getNestedContraints() as $nestedContraint) { 192 $this->checkConstraint($nestedContraint); 193 } 194 } 195 } 196} 197