1<?php
2/**
3 * Zend Framework (http://framework.zend.com/)
4 *
5 * @link      http://github.com/zendframework/zf2 for the canonical source repository
6 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
7 * @license   http://framework.zend.com/license/new-bsd New BSD License
8 */
9
10namespace Zend\Validator;
11
12class Callback extends AbstractValidator
13{
14    /**
15     * Invalid callback
16     */
17    const INVALID_CALLBACK = 'callbackInvalid';
18
19    /**
20     * Invalid value
21     */
22    const INVALID_VALUE = 'callbackValue';
23
24    /**
25     * Validation failure message template definitions
26     *
27     * @var array
28     */
29    protected $messageTemplates = array(
30        self::INVALID_VALUE    => "The input is not valid",
31        self::INVALID_CALLBACK => "An exception has been raised within the callback",
32    );
33
34    /**
35     * Default options to set for the validator
36     *
37     * @var mixed
38     */
39    protected $options = array(
40        'callback'         => null,     // Callback in a call_user_func format, string || array
41        'callbackOptions'  => array(),  // Options for the callback
42    );
43
44    /**
45     * Constructor
46     *
47     * @param array|callable $options
48     */
49    public function __construct($options = null)
50    {
51        if (is_callable($options)) {
52            $options = array('callback' => $options);
53        }
54
55        parent::__construct($options);
56    }
57
58    /**
59     * Returns the set callback
60     *
61     * @return mixed
62     */
63    public function getCallback()
64    {
65        return $this->options['callback'];
66    }
67
68    /**
69     * Sets the callback
70     *
71     * @param  string|array|callable $callback
72     * @return Callback Provides a fluent interface
73     * @throws Exception\InvalidArgumentException
74     */
75    public function setCallback($callback)
76    {
77        if (!is_callable($callback)) {
78            throw new Exception\InvalidArgumentException('Invalid callback given');
79        }
80
81        $this->options['callback'] = $callback;
82        return $this;
83    }
84
85    /**
86     * Returns the set options for the callback
87     *
88     * @return mixed
89     */
90    public function getCallbackOptions()
91    {
92        return $this->options['callbackOptions'];
93    }
94
95    /**
96     * Sets options for the callback
97     *
98     * @param  mixed $options
99     * @return Callback Provides a fluent interface
100     */
101    public function setCallbackOptions($options)
102    {
103        $this->options['callbackOptions'] = (array) $options;
104        return $this;
105    }
106
107    /**
108     * Returns true if and only if the set callback returns
109     * for the provided $value
110     *
111     * @param  mixed $value
112     * @param  mixed $context Additional context to provide to the callback
113     * @return bool
114     * @throws Exception\InvalidArgumentException
115     */
116    public function isValid($value, $context = null)
117    {
118        $this->setValue($value);
119
120        $options  = $this->getCallbackOptions();
121        $callback = $this->getCallback();
122        if (empty($callback)) {
123            throw new Exception\InvalidArgumentException('No callback given');
124        }
125
126        $args = array($value);
127        if (empty($options) && !empty($context)) {
128            $args[] = $context;
129        }
130        if (!empty($options) && empty($context)) {
131            $args = array_merge($args, $options);
132        }
133        if (!empty($options) && !empty($context)) {
134            $args[] = $context;
135            $args   = array_merge($args, $options);
136        }
137
138        try {
139            if (!call_user_func_array($callback, $args)) {
140                $this->error(self::INVALID_VALUE);
141                return false;
142            }
143        } catch (\Exception $e) {
144            $this->error(self::INVALID_CALLBACK);
145            return false;
146        }
147
148        return true;
149    }
150}
151