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\View;
11
12use ArrayObject;
13
14/**
15 * Class for Zend\View\Renderer\PhpRenderer to help enforce private constructs.
16 *
17 * @todo       Allow specifying string names for manager, filter chain, variables
18 * @todo       Move escaping into variables object
19 * @todo       Move strict variables into variables object
20 */
21class Variables extends ArrayObject
22{
23    /**
24     * Strict variables flag; when on, undefined variables accessed in the view
25     * scripts will trigger notices
26     *
27     * @var bool
28     */
29    protected $strictVars = false;
30
31    /**
32     * Constructor
33     *
34     * @param  array $variables
35     * @param  array $options
36     */
37    public function __construct(array $variables = array(), array $options = array())
38    {
39        parent::__construct(
40            $variables,
41            ArrayObject::ARRAY_AS_PROPS,
42            'ArrayIterator'
43        );
44
45        $this->setOptions($options);
46    }
47
48    /**
49     * Configure object
50     *
51     * @param  array $options
52     * @return Variables
53     */
54    public function setOptions(array $options)
55    {
56        foreach ($options as $key => $value) {
57            switch (strtolower($key)) {
58                case 'strict_vars':
59                    $this->setStrictVars($value);
60                    break;
61                default:
62                    // Unknown options are considered variables
63                    $this[$key] = $value;
64                    break;
65            }
66        }
67        return $this;
68    }
69
70    /**
71     * Set status of "strict vars" flag
72     *
73     * @param  bool $flag
74     * @return Variables
75     */
76    public function setStrictVars($flag)
77    {
78        $this->strictVars = (bool) $flag;
79        return $this;
80    }
81
82    /**
83     * Are we operating with strict variables?
84     *
85     * @return bool
86     */
87    public function isStrict()
88    {
89        return $this->strictVars;
90    }
91
92    /**
93     * Assign many values at once
94     *
95     * @param  array|object $spec
96     * @return Variables
97     * @throws Exception\InvalidArgumentException
98     */
99    public function assign($spec)
100    {
101        if (is_object($spec)) {
102            if (method_exists($spec, 'toArray')) {
103                $spec = $spec->toArray();
104            } else {
105                $spec = (array) $spec;
106            }
107        }
108        if (!is_array($spec)) {
109            throw new Exception\InvalidArgumentException(sprintf(
110                'assign() expects either an array or an object as an argument; received "%s"',
111                gettype($spec)
112            ));
113        }
114        foreach ($spec as $key => $value) {
115            $this[$key] = $value;
116        }
117
118        return $this;
119    }
120
121    /**
122     * Get the variable value
123     *
124     * If the value has not been defined, a null value will be returned; if
125     * strict vars on in place, a notice will also be raised.
126     *
127     * Otherwise, returns _escaped_ version of the value.
128     *
129     * @param  mixed $key
130     * @return mixed
131     */
132    public function offsetGet($key)
133    {
134        if (!$this->offsetExists($key)) {
135            if ($this->isStrict()) {
136                trigger_error(sprintf(
137                    'View variable "%s" does not exist',
138                    $key
139                ), E_USER_NOTICE);
140            }
141            return;
142        }
143
144        $return = parent::offsetGet($key);
145
146        // If we have a closure/functor, invoke it, and return its return value
147        if (is_object($return) && is_callable($return)) {
148            $return = call_user_func($return);
149        }
150
151        return $return;
152    }
153
154    /**
155     * Clear all variables
156     *
157     * @return void
158     */
159    public function clear()
160    {
161        $this->exchangeArray(array());
162    }
163}
164