Completed
Push — master ( ec2c00...c3f83b )
by Markus
05:40
created

SampleAppLanguageRoutingCallback::getShortestLocaleIdentifier()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 14
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 9
nc 4
nop 1
dl 0
loc 14
rs 9.2
c 0
b 0
f 0
1
<?php
2
3
use Agavi\Core\Context;
4
use Agavi\Controller\ExecutionContainer;
5
6
class SampleAppLanguageRoutingCallback extends Agavi\Routing\RoutingCallback
7
{
8
	protected $availableLocales = array();
9
    protected $translationManager = null;
10
	
11
	public function initialize(Context $context, array &$route)
12
	{
13
		parent::initialize($context, $route);
14
		
15
		// reduce method calls
16
		$this->translationManager = $this->context->getTranslationManager();
17
		
18
		// store the available locales, that's faster
19
		$this->availableLocales = $this->context->getTranslationManager()->getAvailableLocales();
20
	}
21
	
22
	public function onMatched(array &$parameters, ExecutionContainer $container)
23
	{
24
		// let's check if the locale is allowed
25
		try {
26
			$set = $this->context->getTranslationManager()->getLocaleIdentifier($parameters['locale']);
27
			// yup, worked. now lets set that as a cookie
28
			$this->context->getController()->getGlobalResponse()->setCookie('locale', $parameters['locale'], '+1 month');
29
			return true;
30
		} catch(Exception $e) {
31
			// uregistered or ambigious locale... uncool!
32
			// onNotMatched will be called for us next
33
			return false;
34
		}
35
	}
36
37
	public function onNotMatched(ExecutionContainer $container)
38
	{
39
		// the pattern didn't match, or onMatched() returned false.
40
		// that's sad. let's see if there's a locale set in a cookie from an earlier visit.
41
		$rd = $this->context->getRequest()->getRequestData();
42
		
43
		$cookie = $rd->getCookie('locale');
44
		if($cookie !== null) {
45
			try {
46
				$this->translationManager->setLocale($cookie);
47
				return;
48
			} catch(Exception $e) {
49
				// bad cookie :<
50
				$this->context->getController()->getGlobalResponse()->unsetCookie('locale');
51
			}
52
		}
53
		
54
		if($rd->hasHeader('Accept-Language')) {
55
			$hasIntl = function_exists('locale_accept_from_http');
56
			// try to find the best match for the locale
57
			$locales = self::parseAcceptLanguage($rd->getHeader('Accept-Language'));
58
			foreach($locales as $locale) {
59
				try {
60
					if($hasIntl) {
61
						// we don't use this directly on Accept-Language because we might not have the preferred locale, but another one
62
						// in any case, it might help clean up the value a bit further
63
						$locale = locale_accept_from_http($locale);
64
					}
65
					$this->translationManager->setLocale($locale);
66
					return;
67
				} catch(Exception $e) {
68
				}
69
			}
70
		}
71
	}
72
73
	public function onGenerate(array $defaultParameters, array &$userParameters, array &$options)
74
	{
75
		if(isset($userParameters['locale'])) {
76
			$userParameters['locale'] = $this->getShortestLocaleIdentifier($userParameters['locale']);
77
		} else {
78
			$userParameters['locale'] = $this->getShortestLocaleIdentifier($this->translationManager->getCurrentLocaleIdentifier());
79
		}
80
		return true;
81
	}
82
	
83
	public function getShortestLocaleIdentifier($localeIdentifier)
84
	{
85
		static $localeMap = null;
86
		if($localeMap === null) {
87
			foreach($this->availableLocales as $locale) {
88
				$localeMap[$locale['identifierData']['language']][] = $locale['identifierData']['territory'];
89
			}
90
		}
91
		if(count($localeMap[$short = substr($localeIdentifier, 0, 2)]) > 1) {
92
			return $localeIdentifier;
93
		} else {
94
			return $short;
95
		}
96
	}
97
	
98
	protected static function parseAcceptLanguage($acceptLanguage)
99
	{
100
		$locales = array();
101
		
102
		if(preg_match_all('/(^|\s*,\s*)([a-zA-Z]{1,8}(-[a-zA-Z]{1,8})*)\s*(;\s*q\s*=\s*(1(\.0{0,3})?|0(\.[0-9]{0,3})))?/i', $acceptLanguage, $matches)) {
103
			foreach($matches[2] as &$language) {
104
				$language = str_replace('-', '_', $language);
105
			}
106
			foreach($matches[5] as &$quality) {
107
				if($quality === '') {
108
					$quality = '1';
109
				}
110
			}
111
			$locales = array_combine($matches[2], $matches[5]);
112
			arsort($locales, SORT_NUMERIC);
113
		}
114
		
115
		return array_keys($locales);
116
	}
117
}
118
119
?>