1: <?php
2:
3: /**
4: * Copyright 2015, Eduardo Trujillo
5: *
6: * For the full copyright and license information, please view the LICENSE
7: * file that was distributed with this source code.
8: *
9: * This file is part of the Nucleus package
10: */
11:
12: namespace Chromabits\Nucleus\Validation;
13:
14: use Chromabits\Nucleus\Foundation\BaseObject;
15: use Chromabits\Nucleus\Meditation\Constraints\AbstractConstraint;
16: use Chromabits\Nucleus\Meditation\Interfaces\CheckableInterface;
17: use Chromabits\Nucleus\Meditation\Spec;
18: use Chromabits\Nucleus\Meditation\SpecResult;
19: use Chromabits\Nucleus\Support\Arr;
20: use Chromabits\Nucleus\Support\Std;
21:
22: /**
23: * Class Validator.
24: *
25: * An extension of Spec, which supports displaying more user-friendly messages.
26: *
27: * @author Eduardo Trujillo <ed@chromabits.com>
28: * @package Chromabits\Nucleus\Validation
29: */
30: class Validator extends BaseObject implements CheckableInterface
31: {
32: /**
33: * @var array
34: */
35: protected $messages;
36:
37: /**
38: * @var Spec
39: */
40: protected $spec;
41:
42: /**
43: * Construct an instance of a Validator.
44: *
45: * @param CheckableInterface $spec
46: * @param array $messages
47: */
48: public function __construct(CheckableInterface $spec, array $messages = [])
49: {
50: parent::__construct();
51:
52: $this->spec = $spec;
53: $this->messages = $messages;
54: }
55:
56: /**
57: * Construct an instance of a Validator.
58: *
59: * @param CheckableInterface $spec
60: * @param array $messages
61: *
62: * @return static
63: * @deprecated
64: */
65: public static function create(
66: CheckableInterface $spec,
67: array $messages = []
68: ) {
69: return new static($spec, $messages);
70: }
71:
72: /**
73: * Construct an instance of a Validator.
74: *
75: * @param CheckableInterface $spec
76: * @param array $messages
77: *
78: * @return static
79: */
80: public static function define(
81: CheckableInterface $spec,
82: array $messages = []
83: ) {
84: return new static($spec, $messages);
85: }
86:
87: /**
88: * Shortcut for defining a validator using a Spec.
89: *
90: * @param array $constraints
91: * @param array $defaults
92: * @param array $required
93: * @param array $messages
94: *
95: * @return static
96: */
97: public static function spec(
98: $constraints,
99: $defaults = [],
100: $required = [],
101: $messages = []
102: ) {
103: return new static(
104: Spec::define($constraints, $defaults, $required),
105: $messages
106: );
107: }
108:
109: /**
110: * @return string[]
111: */
112: public function getMessages()
113: {
114: return $this->messages;
115: }
116:
117: /**
118: * @return Spec
119: */
120: public function getSpec()
121: {
122: return $this->spec;
123: }
124:
125: /**
126: * Check that the spec matches and overlay help messaged.
127: *
128: * The resulting SpecResult instance should have more user-friendly
129: * messages. This allows one to use Specs for validation on a website or
130: * even an API.
131: *
132: * @param array $input
133: *
134: * @return SpecResult
135: */
136: public function check(array $input)
137: {
138: $result = $this->spec->check($input);
139:
140: return new SpecResult(
141: $result->getMissing(),
142: Arr::walkCopy(
143: $result->getFailed(),
144: function ($key, $value, &$array, $path) {
145: $array[$key] = Std::coalesce(
146: Std::firstBias(
147: Arr::dotGet(
148: $this->messages,
149: Std::nonempty($path, $key)
150: ) !== null,
151: [Arr::dotGet(
152: $this->messages,
153: Std::nonempty($path, $key)
154: )],
155: null
156: ),
157: Std::firstBias(
158: $value instanceof AbstractConstraint,
159: function () use ($value) {
160: return $value->getDescription();
161: },
162: null
163: ),
164: Std::firstBias(
165: is_array($value),
166: function () use ($value) {
167: return array_map(
168: function (AbstractConstraint $item) {
169: return $item->getDescription();
170: },
171: $value
172: );
173: },
174: $value
175: )
176: );
177: },
178: true,
179: '',
180: false
181: ),
182: $result->getStatus()
183: );
184: }
185: }
186: