TranslationConfigHandler   A
last analyzed

Complexity

Total Complexity 26

Size/Duplication

Total Lines 175
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 5

Importance

Changes 0
Metric Value
dl 0
loc 175
rs 10
c 0
b 0
f 0
wmc 26
lcom 1
cbo 5

3 Methods

Rating   Name   Duplication   Size   Complexity  
C execute() 0 70 11
B getFilters() 0 17 5
D getTranslators() 0 46 10
1
<?php
2
3
// +---------------------------------------------------------------------------+
4
// | This file is part of the Agavi package.                                   |
5
// | Copyright (c) 2005-2011 the Agavi Project.                                |
6
// |                                                                           |
7
// | For the full copyright and license information, please view the LICENSE   |
8
// | file that was distributed with this source code. You can also view the    |
9
// | LICENSE file online at http://www.agavi.org/LICENSE.txt                   |
10
// |   vi: set noexpandtab:                                                    |
11
// |   Local Variables:                                                        |
12
// |   indent-tabs-mode: t                                                     |
13
// |   End:                                                                    |
14
// +---------------------------------------------------------------------------+
15
16
namespace Agavi\Config;
17
18
use Agavi\Config\Util\Dom\XmlConfigDomDocument;
19
use Agavi\Config\Util\Dom\XmlConfigDomElement;
20
use Agavi\Exception\ConfigurationException;
21
use Agavi\Translation\Locale;
22
23
/**
24
 * TranslationConfigHandler allows you to define translator implementations
25
 * for different domains.
26
 *
27
 * @package    agavi
28
 * @subpackage config
29
 *
30
 * @author     Dominik del Bondio <[email protected]>
31
 * @author     David Zülke <[email protected]>
32
 * @copyright  Authors
33
 * @copyright  The Agavi Project
34
 *
35
 * @since      0.11.0
36
 *
37
 * @version    $Id$
38
 */
39
class TranslationConfigHandler extends XmlConfigHandler
40
{
41
    const XML_NAMESPACE = 'http://agavi.org/agavi/config/parts/translation/1.1';
42
    
43
    /**
44
     * Execute this configuration handler.
45
     *
46
     * @param      XmlConfigDomDocument $document The document to parse.
47
     *
48
     * @return     string Data to be written to a cache file.
49
     *
50
     * @throws     <b>ParseException</b> If a requested configuration file is
51
     *                                        improperly formatted.
52
     *
53
     * @author     Dominik del Bondio <[email protected]>
54
     * @author     David Zülke <[email protected]>
55
     * @since      0.11.0
56
     */
57
    public function execute(XmlConfigDomDocument $document)
58
    {
59
        // set up our default namespace
60
        $document->setDefaultNamespace(self::XML_NAMESPACE, 'translation');
61
        
62
        $config = $document->documentURI;
63
        
64
        $translatorData = array();
65
        $localeData = array();
66
67
        $defaultDomain = '';
68
        $defaultLocale = null;
69
        $defaultTimeZone = null;
70
71
        foreach ($document->getConfigurationElements() as $cfg) {
72
            if ($cfg->hasChild('available_locales')) {
73
                /** @var XmlConfigDomElement $availableLocales */
74
                $availableLocales = $cfg->getChild('available_locales');
75
                // TODO: is this really optional? according to the schema: yes...
76
                $defaultLocale = $availableLocales->getAttribute('default_locale', $defaultLocale);
77
                $defaultTimeZone = $availableLocales->getAttribute('default_timezone', $defaultTimeZone);
78
                /** @var XmlConfigDomElement $locale */
79
                foreach ($availableLocales as $locale) {
80
                    $name = $locale->getAttribute('identifier');
81
                    if (!isset($localeData[$name])) {
82
                        $localeData[$name] = array('name' => $name, 'params' => array(), 'fallback' => null, 'ldml_file' => null);
83
                    }
84
                    $localeData[$name]['params'] = $locale->getAgaviParameters($localeData[$name]['params']);
85
                    $localeData[$name]['fallback'] = $locale->getAttribute('fallback', $localeData[$name]['fallback']);
86
                    $localeData[$name]['ldml_file'] = $locale->getAttribute('ldml_file', $localeData[$name]['ldml_file']);
87
                }
88
            }
89
90
            if ($cfg->hasChild('translators')) {
91
                /** @var XmlConfigDomElement $translators */
92
                $translators = $cfg->getChild('translators');
93
                $defaultDomain = $translators->getAttribute('default_domain', $defaultDomain);
94
                $this->getTranslators($translators, $translatorData);
0 ignored issues
show
Documentation introduced by
$translators is of type object<Agavi\Config\Util\Dom\XmlConfigDomElement>, but the function expects a array<integer,object<Aga...m\XmlConfigDomElement>>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
95
            }
96
        }
97
98
        $data = array();
99
100
        $data[] = sprintf('$this->defaultDomain = %s;', var_export($defaultDomain, true));
101
        $data[] = sprintf('$this->defaultLocaleIdentifier = %s;', var_export($defaultLocale, true));
102
        $data[] = sprintf('$this->defaultTimeZone = %s;', var_export($defaultTimeZone, true));
103
104
        foreach ($localeData as $locale) {
105
            // TODO: fallback stuff
106
107
            $data[] = sprintf('$this->availableConfigLocales[%s] = array(\'identifier\' => %s, \'identifierData\' => %s, \'parameters\' => %s);', var_export($locale['name'], true), var_export($locale['name'], true), var_export(Locale::parseLocaleIdentifier($locale['name']), true), var_export($locale['params'], true));
108
        }
109
110
        foreach ($translatorData as $domain => $translator) {
111
            foreach (array('msg', 'num', 'cur', 'date') as $type) {
112
                if (isset($translator[$type]['class'])) {
113
                    if (!class_exists($translator[$type]['class'])) {
114
                        throw new ConfigurationException(sprintf('The Translator or Formatter class "%s" for domain "%s" could not be found.', $translator[$type]['class'], $domain));
115
                    }
116
                    $data[] = join("\n", array(
117
                        sprintf('$this->translators[%s][%s] = new %s();', var_export($domain, true), var_export($type, true), $translator[$type]['class']),
118
                        sprintf('$this->translators[%s][%s]->initialize($this->getContext(), %s);', var_export($domain, true), var_export($type, true), var_export($translator[$type]['params'], true)),
119
                        sprintf('$this->translatorFilters[%s][%s] = %s;', var_export($domain, true), var_export($type, true), var_export($translator[$type]['filters'], true)),
120
                    ));
121
                }
122
            }
123
        }
124
125
        return $this->generate($data, $config);
126
    }
127
    
128
    /**
129
     * Builds a list of filters for a translator.
130
     *
131
     * @param      XmlConfigDomElement $translator The Translator node.
132
     *
133
     * @return     array An array of filter definitions.
134
     *
135
     * @author     David Zülke <[email protected]>
136
     * @since      0.11.0
137
     */
138
    protected function getFilters(XmlConfigDomElement $translator)
139
    {
140
        $filters = array();
141
        if ($translator->has('filters')) {
142
            foreach ($translator->get('filters') as $filter) {
143
                $func = explode('::', $filter->getValue());
144
                if (count($func) != 2) {
145
                    $func = $func[0];
146
                }
147
                if (!is_callable($func)) {
148
                    throw new ConfigurationException('Non-existant or uncallable filter function "' . $filter->getValue() .  '" specified.');
149
                }
150
                $filters[] = $func;
151
            }
152
        }
153
        return $filters;
154
    }
155
156
    /**
157
     * Build a list of translators.
158
     *
159
     * @param      XmlConfigDomElement[] $translators The translators container.
160
     * @param      array                 $data        The destination data array.
161
     * @param      string                $parent      The name of the parent domain.
162
     *
163
     * @author     Dominik del Bondio <[email protected]>
164
     * @author     David Zülke <[email protected]>
165
     * @since      0.11.0
166
     */
167
    protected function getTranslators($translators, &$data, $parent = null)
168
    {
169
        static $defaultData = array(
170
            'msg'  => array('class' => null, 'filters' => array(), 'params' => array()),
171
            'num'  => array('class' => 'Agavi\\Translation\\NumberFormatter', 'filters' => array(), 'params' => array()),
172
            'cur'  => array('class' => 'Agavi\\Translation\\CurrencyFormatter', 'filters' => array(), 'params' => array()),
173
            'date' => array('class' => 'Agavi\\Translation\\DateFormatter', 'filters' => array(), 'params' => array()),
174
        );
175
176
        foreach ($translators as $translator) {
177
            $domain = $translator->getAttribute('domain');
178
            if ($parent) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $parent of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
179
                $domain = $parent . '.' . $domain;
180
            }
181
            if (!isset($data[$domain])) {
182
                if (!$parent) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $parent of type string|null is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
183
                    $data[$domain] = $defaultData;
184
                } else {
185
                    $data[$domain] = array();
186
                }
187
            }
188
189
            $domainData =& $data[$domain];
190
191
            foreach (array('msg' => 'message_translator', 'num' => 'number_formatter', 'cur' => 'currency_formatter', 'date' => 'date_formatter') as $type => $nodeName) {
192
                if ($translator->hasChild($nodeName)) {
193
                    /** @var XmlConfigDomElement $node */
194
                    $node = $translator->getChild($nodeName);
195
                    if (!isset($domainData[$type])) {
196
                        $domainData[$type] = $defaultData[$type];
197
                    }
198
                    
199
                    if ($node->hasAttribute('translation_domain')) {
200
                        $domainData[$type]['params']['translation_domain'] = $node->getAttribute('translation_domain');
201
                    }
202
                    $domainData[$type]['class'] = $node->getAttribute('class', $domainData[$type]['class']);
203
                    $domainData[$type]['params'] = $node->getAgaviParameters($domainData[$type]['params']);
204
                    $domainData[$type]['filters'] = array_merge($domainData[$type]['filters'], $this->getFilters($node));
205
                }
206
            }
207
208
            if ($translator->has('translators')) {
209
                $this->getTranslators($translator->get('translators'), $data, $domain);
0 ignored issues
show
Documentation introduced by
$translator->get('translators') is of type object<DOMNodeList>, but the function expects a array<integer,object<Aga...m\XmlConfigDomElement>>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
210
            }
211
        }
212
    }
213
}
214