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\Resolver;
11
12use ArrayIterator;
13use IteratorAggregate;
14use Traversable;
15use Zend\Stdlib\ArrayUtils;
16use Zend\View\Exception;
17use Zend\View\Renderer\RendererInterface as Renderer;
18
19class TemplateMapResolver implements IteratorAggregate, ResolverInterface
20{
21    /**
22     * @var array
23     */
24    protected $map = array();
25
26    /**
27     * Constructor
28     *
29     * Instantiate and optionally populate template map.
30     *
31     * @param  array|Traversable $map
32     */
33    public function __construct($map = array())
34    {
35        $this->setMap($map);
36    }
37
38    /**
39     * IteratorAggregate: return internal iterator
40     *
41     * @return Traversable
42     */
43    public function getIterator()
44    {
45        return new ArrayIterator($this->map);
46    }
47
48    /**
49     * Set (overwrite) template map
50     *
51     * Maps should be arrays or Traversable objects with name => path pairs
52     *
53     * @param  array|Traversable $map
54     * @throws Exception\InvalidArgumentException
55     * @return TemplateMapResolver
56     */
57    public function setMap($map)
58    {
59        if (!is_array($map) && !$map instanceof Traversable) {
60            throw new Exception\InvalidArgumentException(sprintf(
61                '%s: expects an array or Traversable, received "%s"',
62                __METHOD__,
63                (is_object($map) ? get_class($map) : gettype($map))
64            ));
65        }
66
67        if ($map instanceof Traversable) {
68            $map = ArrayUtils::iteratorToArray($map);
69        }
70
71        $this->map = $map;
72        return $this;
73    }
74
75    /**
76     * Add an entry to the map
77     *
78     * @param  string|array|Traversable $nameOrMap
79     * @param  null|string $path
80     * @throws Exception\InvalidArgumentException
81     * @return TemplateMapResolver
82     */
83    public function add($nameOrMap, $path = null)
84    {
85        if (is_array($nameOrMap) || $nameOrMap instanceof Traversable) {
86            $this->merge($nameOrMap);
87            return $this;
88        }
89
90        if (!is_string($nameOrMap)) {
91            throw new Exception\InvalidArgumentException(sprintf(
92                '%s: expects a string, array, or Traversable for the first argument; received "%s"',
93                __METHOD__,
94                (is_object($nameOrMap) ? get_class($nameOrMap) : gettype($nameOrMap))
95            ));
96        }
97
98        if (empty($path)) {
99            if (isset($this->map[$nameOrMap])) {
100                unset($this->map[$nameOrMap]);
101            }
102            return $this;
103        }
104
105        $this->map[$nameOrMap] = $path;
106        return $this;
107    }
108
109    /**
110     * Merge internal map with provided map
111     *
112     * @param  array|Traversable $map
113     * @throws Exception\InvalidArgumentException
114     * @return TemplateMapResolver
115     */
116    public function merge($map)
117    {
118        if (!is_array($map) && !$map instanceof Traversable) {
119            throw new Exception\InvalidArgumentException(sprintf(
120                '%s: expects an array or Traversable, received "%s"',
121                __METHOD__,
122                (is_object($map) ? get_class($map) : gettype($map))
123            ));
124        }
125
126        if ($map instanceof Traversable) {
127            $map = ArrayUtils::iteratorToArray($map);
128        }
129
130        $this->map = array_replace_recursive($this->map, $map);
131        return $this;
132    }
133
134    /**
135     * Does the resolver contain an entry for the given name?
136     *
137     * @param  string $name
138     * @return bool
139     */
140    public function has($name)
141    {
142        return array_key_exists($name, $this->map);
143    }
144
145    /**
146     * Retrieve a template path by name
147     *
148     * @param  string $name
149     * @return false|string
150     * @throws Exception\DomainException if no entry exists
151     */
152    public function get($name)
153    {
154        if (!$this->has($name)) {
155            return false;
156        }
157        return $this->map[$name];
158    }
159
160    /**
161     * Retrieve the template map
162     *
163     * @return array
164     */
165    public function getMap()
166    {
167        return $this->map;
168    }
169
170    /**
171     * Resolve a template/pattern name to a resource the renderer can consume
172     *
173     * @param  string $name
174     * @param  null|Renderer $renderer
175     * @return string
176     */
177    public function resolve($name, Renderer $renderer = null)
178    {
179        return $this->get($name);
180    }
181}
182