4 * This file is part of the Symfony package.
6 * (c) Fabien Potencier <fabien@symfony.com>
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
12 namespace Symfony\Component\Validator\Constraints;
14 use Symfony\Component\Validator\Context\ExecutionContextInterface;
15 use Symfony\Component\Validator\Constraint;
16 use Symfony\Component\Validator\ConstraintValidator;
17 use Symfony\Component\Validator\Exception\UnexpectedTypeException;
20 * Validates whether the value is a valid ISSN.
22 * @author Antonio J. GarcĂa Lagar <aj@garcialagar.es>
23 * @author Bernhard Schussek <bschussek@gmail.com>
25 * @see https://en.wikipedia.org/wiki/Issn
27 class IssnValidator extends ConstraintValidator
32 public function validate($value, Constraint $constraint)
34 if (!$constraint instanceof Issn) {
35 throw new UnexpectedTypeException($constraint, __NAMESPACE__.'\Issn');
38 if (null === $value || '' === $value) {
42 if (!is_scalar($value) && !(is_object($value) && method_exists($value, '__toString'))) {
43 throw new UnexpectedTypeException($value, 'string');
46 $value = (string) $value;
51 if (isset($canonical[4]) && '-' === $canonical[4]) {
53 $canonical = substr($canonical, 0, 4).substr($canonical, 5);
54 } elseif ($constraint->requireHyphen) {
55 if ($this->context instanceof ExecutionContextInterface) {
56 $this->context->buildViolation($constraint->message)
57 ->setParameter('{{ value }}', $this->formatValue($value))
58 ->setCode(Issn::MISSING_HYPHEN_ERROR)
61 $this->buildViolation($constraint->message)
62 ->setParameter('{{ value }}', $this->formatValue($value))
63 ->setCode(Issn::MISSING_HYPHEN_ERROR)
70 $length = strlen($canonical);
73 if ($this->context instanceof ExecutionContextInterface) {
74 $this->context->buildViolation($constraint->message)
75 ->setParameter('{{ value }}', $this->formatValue($value))
76 ->setCode(Issn::TOO_SHORT_ERROR)
79 $this->buildViolation($constraint->message)
80 ->setParameter('{{ value }}', $this->formatValue($value))
81 ->setCode(Issn::TOO_SHORT_ERROR)
89 if ($this->context instanceof ExecutionContextInterface) {
90 $this->context->buildViolation($constraint->message)
91 ->setParameter('{{ value }}', $this->formatValue($value))
92 ->setCode(Issn::TOO_LONG_ERROR)
95 $this->buildViolation($constraint->message)
96 ->setParameter('{{ value }}', $this->formatValue($value))
97 ->setCode(Issn::TOO_LONG_ERROR)
105 // ^^^^^^^ digits only
106 if (!ctype_digit(substr($canonical, 0, 7))) {
107 if ($this->context instanceof ExecutionContextInterface) {
108 $this->context->buildViolation($constraint->message)
109 ->setParameter('{{ value }}', $this->formatValue($value))
110 ->setCode(Issn::INVALID_CHARACTERS_ERROR)
113 $this->buildViolation($constraint->message)
114 ->setParameter('{{ value }}', $this->formatValue($value))
115 ->setCode(Issn::INVALID_CHARACTERS_ERROR)
124 if (!ctype_digit($canonical[7]) && 'x' !== $canonical[7] && 'X' !== $canonical[7]) {
125 if ($this->context instanceof ExecutionContextInterface) {
126 $this->context->buildViolation($constraint->message)
127 ->setParameter('{{ value }}', $this->formatValue($value))
128 ->setCode(Issn::INVALID_CHARACTERS_ERROR)
131 $this->buildViolation($constraint->message)
132 ->setParameter('{{ value }}', $this->formatValue($value))
133 ->setCode(Issn::INVALID_CHARACTERS_ERROR)
142 if ($constraint->caseSensitive && 'x' === $canonical[7]) {
143 if ($this->context instanceof ExecutionContextInterface) {
144 $this->context->buildViolation($constraint->message)
145 ->setParameter('{{ value }}', $this->formatValue($value))
146 ->setCode(Issn::INVALID_CASE_ERROR)
149 $this->buildViolation($constraint->message)
150 ->setParameter('{{ value }}', $this->formatValue($value))
151 ->setCode(Issn::INVALID_CASE_ERROR)
158 // Calculate a checksum. "X" equals 10.
159 $checkSum = 'X' === $canonical[7]
160 || 'x' === $canonical[7]
164 for ($i = 0; $i < 7; ++$i) {
165 // Multiply the first digit by 8, the second by 7, etc.
166 $checkSum += (8 - $i) * $canonical[$i];
169 if (0 !== $checkSum % 11) {
170 if ($this->context instanceof ExecutionContextInterface) {
171 $this->context->buildViolation($constraint->message)
172 ->setParameter('{{ value }}', $this->formatValue($value))
173 ->setCode(Issn::CHECKSUM_FAILED_ERROR)
176 $this->buildViolation($constraint->message)
177 ->setParameter('{{ value }}', $this->formatValue($value))
178 ->setCode(Issn::CHECKSUM_FAILED_ERROR)