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_Configurable
24 * the base for Doctrine_Table, Doctrine_Manager and Doctrine_Connection
25 *
26 * @package     Doctrine
27 * @subpackage  Configurable
28 * @license     http://www.opensource.org/licenses/lgpl-license.php LGPL
29 * @link        www.doctrine-project.org
30 * @since       1.0
31 * @version     $Revision$
32 * @author      Konsta Vesterinen <kvesteri@cc.hut.fi>
33 */
34abstract class Doctrine_Configurable extends Doctrine_Locator_Injectable
35{
36    /**
37     * @var array $attributes               an array of containing all attributes
38     */
39    protected $attributes = array();
40
41    /**
42     * @var Doctrine_Configurable $parent   the parent of this component
43     */
44    protected $parent;
45
46    /**
47     * @var array $_impl                    an array containing concrete implementations for class templates
48     *                                      keys as template names and values as names of the concrete
49     *                                      implementation classes
50     */
51    protected $_impl = array();
52
53    /**
54     * @var array $_params                  an array of user defined parameters
55     */
56    protected $_params = array();
57
58    /**
59     * setAttribute
60     * sets a given attribute
61     *
62     * <code>
63     * $manager->setAttribute(Doctrine_Core::ATTR_PORTABILITY, Doctrine_Core::PORTABILITY_ALL);
64     * </code>
65     *
66     * @param mixed $attribute              either a Doctrine_Core::ATTR_* integer constant or a string
67     *                                      corresponding to a constant
68     * @param mixed $value                  the value of the attribute
69     * @see Doctrine_Core::ATTR_* constants
70     * @throws Doctrine_Exception           if the value is invalid
71     * @return void
72     */
73    public function setAttribute($attribute, $value)
74    {
75        switch ($attribute) {
76            case Doctrine_Core::ATTR_LISTENER:
77                $this->setEventListener($value);
78                break;
79            case Doctrine_Core::ATTR_COLL_KEY:
80                if ( ! ($this instanceof Doctrine_Table)) {
81                    throw new Doctrine_Exception("This attribute can only be set at table level.");
82                }
83                if ($value !== null && ! $this->hasField($value)) {
84                    throw new Doctrine_Exception("Couldn't set collection key attribute. No such field '$value'.");
85                }
86                break;
87            case Doctrine_Core::ATTR_CACHE:
88            case Doctrine_Core::ATTR_RESULT_CACHE:
89            case Doctrine_Core::ATTR_QUERY_CACHE:
90            case Doctrine_Core::ATTR_TABLE_CACHE:
91                if ($value !== null) {
92                    if ( ! ($value instanceof Doctrine_Cache_Interface)) {
93                        throw new Doctrine_Exception('Cache driver should implement Doctrine_Cache_Interface');
94                    }
95                }
96                break;
97            case Doctrine_Core::ATTR_SEQCOL_NAME:
98                if ( ! is_string($value)) {
99                    throw new Doctrine_Exception('Sequence column name attribute only accepts string values');
100                }
101                break;
102            case Doctrine_Core::ATTR_FIELD_CASE:
103                if ($value != 0 && $value != CASE_LOWER && $value != CASE_UPPER)
104                    throw new Doctrine_Exception('Field case attribute should be either 0, CASE_LOWER or CASE_UPPER constant.');
105                break;
106            case Doctrine_Core::ATTR_SEQNAME_FORMAT:
107            case Doctrine_Core::ATTR_IDXNAME_FORMAT:
108            case Doctrine_Core::ATTR_TBLNAME_FORMAT:
109            case Doctrine_Core::ATTR_FKNAME_FORMAT:
110                if ($this instanceof Doctrine_Table) {
111                    throw new Doctrine_Exception('Sequence / index name format attributes cannot be set'
112                                               . 'at table level (only at connection or global level).');
113                }
114                break;
115        }
116
117        $this->attributes[$attribute] = $value;
118    }
119
120    public function getParams($namespace = null)
121    {
122    	if ($namespace == null) {
123    	    $namespace = $this->getAttribute(Doctrine_Core::ATTR_DEFAULT_PARAM_NAMESPACE);
124    	}
125
126    	if ( ! isset($this->_params[$namespace])) {
127    	    return null;
128    	}
129
130        return $this->_params[$namespace];
131    }
132
133    public function getParamNamespaces()
134    {
135        return array_keys($this->_params);
136    }
137
138    public function setParam($name, $value, $namespace = null)
139    {
140    	if ($namespace == null) {
141    	    $namespace = $this->getAttribute(Doctrine_Core::ATTR_DEFAULT_PARAM_NAMESPACE);
142    	}
143
144    	$this->_params[$namespace][$name] = $value;
145
146    	return $this;
147    }
148
149    public function getParam($name, $namespace = null)
150    {
151    	if ($namespace == null) {
152    	    $namespace = $this->getAttribute(Doctrine_Core::ATTR_DEFAULT_PARAM_NAMESPACE);
153    	}
154
155        if ( ! isset($this->_params[$namespace][$name])) {
156            if (isset($this->parent)) {
157                return $this->parent->getParam($name, $namespace);
158            }
159            return null;
160        }
161
162        return $this->_params[$namespace][$name];
163    }
164
165    /**
166     * setImpl
167     * binds given class to given template name
168     *
169     * this method is the base of Doctrine dependency injection
170     *
171     * @param string $template      name of the class template
172     * @param string $class         name of the class to be bound
173     * @return Doctrine_Configurable    this object
174     */
175    public function setImpl($template, $class)
176    {
177        $this->_impl[$template] = $class;
178
179        return $this;
180    }
181
182    /**
183     * getImpl
184     * returns the implementation for given class
185     *
186     * @return string   name of the concrete implementation
187     */
188    public function getImpl($template)
189    {
190        if ( ! isset($this->_impl[$template])) {
191            if (isset($this->parent)) {
192                return $this->parent->getImpl($template);
193            }
194            return null;
195        }
196        return $this->_impl[$template];
197    }
198
199
200    public function hasImpl($template)
201    {
202        if ( ! isset($this->_impl[$template])) {
203            if (isset($this->parent)) {
204                return $this->parent->hasImpl($template);
205            }
206            return false;
207        }
208        return true;
209    }
210
211    /**
212     * @param Doctrine_EventListener $listener
213     * @return void
214     */
215    public function setEventListener($listener)
216    {
217        return $this->setListener($listener);
218    }
219
220    /**
221     * addRecordListener
222     *
223     * @param Doctrine_EventListener_Interface|Doctrine_Overloadable $listener
224     * @return Doctrine_Configurable        this object
225     */
226    public function addRecordListener($listener, $name = null)
227    {
228        if ( ! isset($this->attributes[Doctrine_Core::ATTR_RECORD_LISTENER]) ||
229             ! ($this->attributes[Doctrine_Core::ATTR_RECORD_LISTENER] instanceof Doctrine_Record_Listener_Chain)) {
230
231            $this->attributes[Doctrine_Core::ATTR_RECORD_LISTENER] = new Doctrine_Record_Listener_Chain();
232        }
233        $this->attributes[Doctrine_Core::ATTR_RECORD_LISTENER]->add($listener, $name);
234
235        return $this;
236    }
237
238    /**
239     * getListener
240     *
241     * @return Doctrine_EventListener_Interface|Doctrine_Overloadable
242     */
243    public function getRecordListener()
244    {
245        if ( ! isset($this->attributes[Doctrine_Core::ATTR_RECORD_LISTENER])) {
246            if (isset($this->parent)) {
247                return $this->parent->getRecordListener();
248            }
249            return null;
250        }
251        return $this->attributes[Doctrine_Core::ATTR_RECORD_LISTENER];
252    }
253
254    /**
255     * setListener
256     *
257     * @param Doctrine_EventListener_Interface|Doctrine_Overloadable $listener
258     * @return Doctrine_Configurable        this object
259     */
260    public function setRecordListener($listener)
261    {
262        if ( ! ($listener instanceof Doctrine_Record_Listener_Interface)
263            && ! ($listener instanceof Doctrine_Overloadable)
264        ) {
265            throw new Doctrine_Exception("Couldn't set eventlistener. Record listeners should implement either Doctrine_Record_Listener_Interface or Doctrine_Overloadable");
266        }
267        $this->attributes[Doctrine_Core::ATTR_RECORD_LISTENER] = $listener;
268
269        return $this;
270    }
271
272    /**
273     * addListener
274     *
275     * @param Doctrine_EventListener_Interface|Doctrine_Overloadable $listener
276     * @return Doctrine_Configurable    this object
277     */
278    public function addListener($listener, $name = null)
279    {
280        if ( ! isset($this->attributes[Doctrine_Core::ATTR_LISTENER]) ||
281             ! ($this->attributes[Doctrine_Core::ATTR_LISTENER] instanceof Doctrine_EventListener_Chain)) {
282
283            $this->attributes[Doctrine_Core::ATTR_LISTENER] = new Doctrine_EventListener_Chain();
284        }
285        $this->attributes[Doctrine_Core::ATTR_LISTENER]->add($listener, $name);
286
287        return $this;
288    }
289
290    /**
291     * getListener
292     *
293     * @return Doctrine_EventListener_Interface|Doctrine_Overloadable
294     */
295    public function getListener()
296    {
297        if ( ! isset($this->attributes[Doctrine_Core::ATTR_LISTENER])) {
298            if (isset($this->parent)) {
299                return $this->parent->getListener();
300            }
301            return null;
302        }
303        return $this->attributes[Doctrine_Core::ATTR_LISTENER];
304    }
305
306    /**
307     * setListener
308     *
309     * @param Doctrine_EventListener_Interface|Doctrine_Overloadable $listener
310     * @return Doctrine_Configurable        this object
311     */
312    public function setListener($listener)
313    {
314        if ( ! ($listener instanceof Doctrine_EventListener_Interface)
315            && ! ($listener instanceof Doctrine_Overloadable)
316        ) {
317            throw new Doctrine_EventListener_Exception("Couldn't set eventlistener. EventListeners should implement either Doctrine_EventListener_Interface or Doctrine_Overloadable");
318        }
319        $this->attributes[Doctrine_Core::ATTR_LISTENER] = $listener;
320
321        return $this;
322    }
323
324    /**
325     * returns the value of an attribute
326     *
327     * @param integer $attribute
328     * @return mixed
329     */
330    public function getAttribute($attribute)
331    {
332        if (isset($this->attributes[$attribute])) {
333            return $this->attributes[$attribute];
334        }
335
336        if (isset($this->parent)) {
337            return $this->parent->getAttribute($attribute);
338        }
339        return null;
340    }
341
342    /**
343     * Unset an attribute from this levels attributes
344     *
345     * @param integer $attribute
346     * @return void
347     */
348    public function unsetAttribute($attribute)
349    {
350        if (isset($this->attributes[$attribute])) {
351            unset($this->attributes[$attribute]);
352        }
353    }
354
355    /**
356     * getAttributes
357     * returns all attributes as an array
358     *
359     * @return array
360     */
361    public function getAttributes()
362    {
363        return $this->attributes;
364    }
365
366    /**
367     * Set the charset
368     *
369     * @param string $charset
370     */
371    public function setCharset($charset)
372    {
373        $this->setAttribute(Doctrine_Core::ATTR_DEFAULT_TABLE_CHARSET, $charset);
374    }
375
376    /**
377     * Get the charset
378     *
379     * @return mixed
380     */
381    public function getCharset()
382    {
383        return $this->getAttribute(Doctrine_Core::ATTR_DEFAULT_TABLE_CHARSET);
384    }
385
386    /**
387     * Set the collate
388     *
389     * @param string $collate
390     */
391    public function setCollate($collate)
392    {
393        $this->setAttribute(Doctrine_Core::ATTR_DEFAULT_TABLE_COLLATE, $collate);
394    }
395
396    /**
397     * Get the collate
398     *
399     * @return mixed $collate
400     */
401    public function getCollate()
402    {
403        return $this->getAttribute(Doctrine_Core::ATTR_DEFAULT_TABLE_COLLATE);
404    }
405
406    /**
407     * sets a parent for this configurable component
408     * the parent must be configurable component itself
409     *
410     * @param Doctrine_Configurable $component
411     * @return void
412     */
413    public function setParent(Doctrine_Configurable $component)
414    {
415        $this->parent = $component;
416    }
417
418    /**
419     * getParent
420     * returns the parent of this component
421     *
422     * @return Doctrine_Configurable
423     */
424    public function getParent()
425    {
426        return $this->parent;
427    }
428}
429