/**
  * @dataProvider provideFetchLanguageCodes
  */
 public function testGetFetchLanguageCodes(array $languages)
 {
     $languagesWithConversion = array();
     foreach ($languages as $language) {
         $languagesWithConversion[] = LanguageWithConversion::factory($language);
     }
     $chain = new LanguageFallbackChain($languagesWithConversion);
     $codes = $chain->getFetchLanguageCodes();
     $this->assertEquals($languages, $codes);
 }
 public function provideGetLabelDescriptionLookup()
 {
     $termLookup = $this->getMock('Wikibase\\DataModel\\Services\\Lookup\\TermLookup');
     $termLookup->expects($this->any())->method('getLabel')->will($this->returnCallback(function ($item, $language) {
         if ($language === 'de') {
             return 'Kätzchen';
         }
         throw new OutOfBoundsException('no bananas');
     }));
     $termLookup->expects($this->any())->method('getLabels')->will($this->returnValue(array('de' => 'Kätzchen')));
     $labelDescriptionLookup = new LanguageLabelDescriptionLookup($termLookup, 'de');
     $deChChain = new LanguageFallbackChain(array(LanguageWithConversion::factory('de-ch'), LanguageWithConversion::factory('de')));
     $frChain = new LanguageFallbackChain(array(LanguageWithConversion::factory('fr')));
     return array('language' => array($termLookup, new FormatterOptions(array(ValueFormatter::OPT_LANG => 'de')), 'Kätzchen'), 'language and fallback chain' => array($termLookup, new FormatterOptions(array(ValueFormatter::OPT_LANG => 'fr', FormatterLabelDescriptionLookupFactory::OPT_LANGUAGE_FALLBACK_CHAIN => $deChChain)), 'Kätzchen'), 'language and fallback chain and LabelDescriptionLookup' => array($termLookup, new FormatterOptions(array(ValueFormatter::OPT_LANG => 'fr', FormatterLabelDescriptionLookupFactory::OPT_LANGUAGE_FALLBACK_CHAIN => $frChain, FormatterLabelDescriptionLookupFactory::OPT_LABEL_DESCRIPTION_LOOKUP => $labelDescriptionLookup)), 'Kätzchen'));
 }
 /**
  * Build fallback chain array for a given language or validated language code.
  *
  * @param Language|string $language Language object or language code as string
  * @param int $mode Bitfield of self::FALLBACK_*
  * @param LanguageFallbackChain[] $chain for recursive calls
  * @param array $fetched for recursive calls
  *
  * @throws InvalidArgumentException
  * @return LanguageWithConversion[]
  */
 private function buildFromLanguage($language, $mode, &$chain = array(), &$fetched = array())
 {
     if (!is_int($mode)) {
         throw new InvalidArgumentException('$mode must be an integer');
     }
     if (is_string($language)) {
         $languageCode = $language;
     } else {
         $languageCode = $language->getCode();
     }
     if ($mode & self::FALLBACK_SELF) {
         if (!isset($fetched[$languageCode])) {
             $chain[] = LanguageWithConversion::factory($language);
             $fetched[$languageCode] = true;
         }
     }
     if ($mode & self::FALLBACK_VARIANTS) {
         /** @var Language $parentLanguage */
         $pieces = explode('-', $languageCode);
         if (!in_array($pieces[0], LanguageConverter::$languagesWithVariants)) {
             $parentLanguage = null;
         } else {
             if (is_string($language)) {
                 $language = Language::factory($language);
             }
             $parentLanguage = $language->getParentLanguage();
         }
         if ($parentLanguage) {
             // It's less likely to trigger conversion mistakes by converting
             // zh-tw to zh-hk first instead of converting zh-cn to zh-tw.
             $variantFallbacks = $parentLanguage->getConverter()->getVariantFallbacks($languageCode);
             if (is_array($variantFallbacks)) {
                 $variants = array_unique(array_merge($variantFallbacks, $parentLanguage->getVariants()));
             } else {
                 $variants = $parentLanguage->getVariants();
             }
             foreach ($variants as $variant) {
                 if (isset($fetched[$variant]) || !$parentLanguage->hasVariant($variant)) {
                     continue;
                 }
                 $chain[] = LanguageWithConversion::factory($language, $variant);
                 $fetched[$variant] = true;
             }
         }
     }
     if ($mode & self::FALLBACK_OTHERS) {
         // Regarding $mode in recursive calls:
         // * self is a must to have the fallback item itself included;
         // * respect the original caller about whether to include variants or not;
         // * others should be excluded as they'll be handled here in loops.
         $recursiveMode = $mode;
         $recursiveMode &= self::FALLBACK_VARIANTS;
         $recursiveMode |= self::FALLBACK_SELF;
         foreach (Language::getFallbacksFor($languageCode) as $other) {
             $this->buildFromLanguage($other, $recursiveMode, $chain, $fetched);
         }
     }
     return $chain;
 }
 private function getLinkBeginHookHandler()
 {
     $languageFallback = new LanguageFallbackChain(array(LanguageWithConversion::factory('de-ch'), LanguageWithConversion::factory('de'), LanguageWithConversion::factory('en')));
     return new LinkBeginHookHandler($this->getEntityIdLookup(), $this->getTermLookup(), $this->getEntityNamespaceLookup(), $languageFallback, Language::factory('en'));
 }