1<?php
2/**
3 *  $Id$
4 *
5 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
6 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
7 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
8 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
9 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
10 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
11 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
12 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
13 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
14 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
15 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
16 *
17 * This software consists of voluntary contributions made by many individuals
18 * and is licensed under the LGPL. For more information, see
19 * <http://www.doctrine-project.org>.
20 */
21
22/**
23 * Doctrine_Locator
24 *
25 * @package     Doctrine
26 * @subpackage  Doctrine_Locator
27 * @category    Locator
28 * @license     http://www.gnu.org/licenses/lgpl.txt LGPL
29 * @link        http://www.doctrine-project.org
30 * @author      Janne Vanhala <jpvanhal@cc.hut.fi>
31 * @author      Konsta Vesterinen <kvesteri@cc.hut.fi>
32 * @author      Eevert Saukkokoski <dmnEe0@gmail.com>
33 * @version     $Revision$
34 * @since       1.0
35 */
36class Doctrine_Locator implements Countable, IteratorAggregate
37{
38    /**
39     * @var array $_resources       an array of bound resources
40     */
41    protected $_resources = array();
42
43    /**
44     * @var string $_classPrefix    the default class prefix
45     */
46    protected $_classPrefix = 'Doctrine_';
47
48    /**
49     * @var array $_instances       a pool of this object's instances
50     */
51    protected static $_instances = array();
52
53    /**
54     * Constructor. Provide an array of resources to set initial contents.
55     *
56     * @param array
57     * @return void
58     */
59    public function __construct(array $defaults = null)
60    {
61        if (null !== $defaults) {
62            foreach ($defaults as $name => $resource) {
63                if ($resource instanceof Doctrine_Locator_Injectable) {
64                    $resource->setLocator($this);
65                }
66                $this->_resources[$name] = $resource;
67            }
68        }
69        self::$_instances[] = $this;
70    }
71
72    /**
73     * instance
74     *
75     * @return Sensei_Locator
76     */
77    public static function instance()
78    {
79        if (empty(self::$_instances)) {
80            $obj = new Doctrine_Locator();
81        }
82        return current(self::$_instances);
83    }
84
85    /**
86     * setClassPrefix
87     *
88     * @param string $prefix
89     */
90    public function setClassPrefix($prefix)
91    {
92        $this->_classPrefix = $prefix;
93    }
94
95    /**
96     * getClassPrefix
97     *
98     * @return string
99     */
100    public function getClassPrefix()
101    {
102        return $this->_classPrefix;
103    }
104
105    /**
106     * contains
107     * checks if a resource exists under the given name
108     *
109     * @return boolean      whether or not given resource name exists
110     */
111    public function contains($name)
112    {
113        return isset($this->_resources[$name]);
114    }
115
116    /**
117     * bind
118     * binds a resource to a name
119     *
120     * @param string $name      the name of the resource to bind
121     * @param mixed $value      the value of the resource
122     * @return Sensei_Locator   this object
123     */
124    public function bind($name, $value)
125    {
126        $this->_resources[$name] = $value;
127
128        return $this;
129    }
130
131    /**
132     * locate
133     * locates a resource by given name and returns it
134     *
135     * @throws Doctrine_Locator_Exception     if the resource could not be found
136     * @param string $name      the name of the resource
137     * @return mixed            the located resource
138     */
139    public function locate($name)
140    {
141        if (isset($this->_resources[$name])) {
142            return $this->_resources[$name];
143        } else {
144            $className = $name;
145
146            if ( ! class_exists($className)) {
147
148                $name = explode('.', $name);
149                foreach ($name as &$v) {
150                    $v = ucfirst(strtolower($v));
151                }
152                $name = implode('_', $name);
153
154                $className = $this->_classPrefix . $name;
155
156                if ( ! class_exists($className)) {
157                    throw new Doctrine_Locator_Exception("Couldn't locate resource " . $className);
158                }
159            }
160
161            $this->_resources[$name] = new $className();
162
163            if ($this->_resources[$name] instanceof Doctrine_Locator_Injectable) {
164                $this->_resources[$name]->setLocator($this);
165            }
166
167            return $this->_resources[$name];
168        }
169
170        throw new Doctrine_Locator_Exception("Couldn't locate resource " . $name);
171    }
172
173    /**
174     * count
175     * returns the number of bound resources associated with
176     * this object
177     *
178     * @see Countable interface
179     * @return integer              the number of resources
180     */
181    public function count()
182    {
183        return count($this->_resources);
184    }
185
186    /**
187     * getIterator
188     * returns an ArrayIterator that iterates through all
189     * bound resources
190     *
191     * @return ArrayIterator    an iterator for iterating through
192     *                          all bound resources
193     */
194    public function getIterator()
195    {
196        return new ArrayIterator($this->_resources);
197    }
198}
199