/** * Create and populate a data collection object from a resource folder * * @param string $resourceFolder * * @throws \LogicException * @return \Browscap\Data\DataCollection */ public function createDataCollection($resourceFolder) { if (null === $this->collection) { throw new \LogicException('An instance of \\Browscap\\Data\\DataCollection is required for this function. ' . 'Please set it with setDataCollection'); } $this->getLogger()->debug('add platform file'); $this->collection->addDevicesFile($resourceFolder . '/devices.json')->addPlatformsFile($resourceFolder . '/platforms.json')->addEnginesFile($resourceFolder . '/engines.json')->addDefaultProperties($resourceFolder . '/core/default-properties.json')->addDefaultBrowser($resourceFolder . '/core/default-browser.json'); $uaSourceDirectory = $resourceFolder . '/user-agents'; $iterator = new \RecursiveDirectoryIterator($uaSourceDirectory); foreach (new \RecursiveIteratorIterator($iterator) as $file) { /** @var $file \SplFileInfo */ if (!$file->isFile() || $file->getExtension() != 'json') { continue; } $this->getLogger()->debug('add source file ' . $file->getPathname()); $this->collection->addSourceFile($file->getPathname()); } return $this->collection; }
/** * renders all found useragents into a string * * @param string[] $section * @param \Browscap\Data\DataCollection $collection * @param array[] $sections * @param string $sectionName * * @throws \InvalidArgumentException * @return XmlWriter */ public function renderSectionBody(array $section, DataCollection $collection, array $sections = array(), $sectionName = '') { if ($this->isSilent()) { return $this; } $division = $collection->getDefaultProperties(); $ua = $division->getUserAgents(); $defaultproperties = $ua[0]['properties']; $properties = array_merge(array('Parent'), array_keys($defaultproperties)); foreach ($section as $property => $propertyValue) { $section[$property] = trim($propertyValue); } foreach ($properties as $property) { if (!isset($section[$property])) { continue; } if (!isset($this->outputProperties[$property])) { $this->outputProperties[$property] = $this->getFilter()->isOutputProperty($property, $this); } if (!$this->outputProperties[$property]) { continue; } fputs($this->file, '<item name="' . $this->getFormatter()->formatPropertyName($property) . '" value="' . $this->getFormatter()->formatPropertyValue($section[$property], $property) . '"/>' . PHP_EOL); } return $this; }
/** * renders all found useragents into a string * * @param string[] $section * @param \Browscap\Data\DataCollection $collection * @param array[] $sections * @param string $sectionName * * @throws \InvalidArgumentException * @return JsonWriter */ public function renderSectionBody(array $section, DataCollection $collection, array $sections = [], $sectionName = '') { if ($this->isSilent()) { return $this; } $division = $collection->getDefaultProperties(); $ua = $division->getUserAgents(); $defaultproperties = $ua[0]['properties']; $properties = array_merge(['Parent'], array_keys($defaultproperties)); foreach ($defaultproperties as $propertyName => $propertyValue) { $defaultproperties[$propertyName] = $this->expander->trimProperty($propertyValue); } $propertiesToOutput = []; foreach ($properties as $property) { if (!isset($section[$property])) { continue; } if (!isset($this->outputProperties[$property])) { $this->outputProperties[$property] = $this->getFilter()->isOutputProperty($property, $this); } if (!$this->outputProperties[$property]) { continue; } if (isset($section['Parent']) && 'Parent' !== $property) { if ('DefaultProperties' === $section['Parent'] || !isset($sections[$section['Parent']])) { if (isset($defaultproperties[$property]) && $defaultproperties[$property] === $section[$property]) { continue; } } else { $parentProperties = $sections[$section['Parent']]; if (isset($parentProperties[$property]) && $parentProperties[$property] === $section[$property]) { continue; } } } $propertiesToOutput[$property] = $section[$property]; } fputs($this->file, $this->getFormatter()->formatPropertyValue(json_encode($propertiesToOutput), 'Comment')); return $this; }
/** * expands all properties for all useragents to make sure all properties are set and make it possible to skip * incomplete properties and remove duplicate definitions * * @param array $allInputDivisions * * @throws \UnexpectedValueException * @return array */ private function expandProperties(array $allInputDivisions) { $this->getLogger()->debug('expand all properties'); $allDivisions = array(); $ua = $this->collection->getDefaultProperties()->getUserAgents(); $defaultproperties = $ua[0]['properties']; foreach (array_keys($allInputDivisions) as $key) { $this->getLogger()->debug('expand all properties for key "' . $key . '"'); $userAgent = $key; $parents = array($userAgent); while (isset($allInputDivisions[$userAgent]['Parent'])) { if ($userAgent === $allInputDivisions[$userAgent]['Parent']) { break; } $parents[] = $allInputDivisions[$userAgent]['Parent']; $userAgent = $allInputDivisions[$userAgent]['Parent']; } unset($userAgent); $parents = array_reverse($parents); $browserData = $defaultproperties; $properties = $allInputDivisions[$key]; foreach ($parents as $parent) { if (!isset($allInputDivisions[$parent])) { continue; } if (!is_array($allInputDivisions[$parent])) { throw new \UnexpectedValueException('Parent "' . $parent . '" is not an array for key "' . $key . '"'); } if ($key !== $parent && isset($allInputDivisions[$parent]['sortIndex']) && isset($properties['sortIndex']) && $allInputDivisions[$parent]['division'] !== $properties['division']) { if ($allInputDivisions[$parent]['sortIndex'] >= $properties['sortIndex']) { throw new \UnexpectedValueException('sorting not ready for key "' . $key . '"'); } } $browserData = array_merge($browserData, $allInputDivisions[$parent]); } array_pop($parents); $browserData['Parents'] = implode(',', $parents); unset($parents); foreach (array_keys($browserData) as $propertyName) { $properties[$propertyName] = $this->trimProperty($browserData[$propertyName]); } unset($browserData); $allDivisions[$key] = $properties; if (!isset($properties['Version'])) { throw new \UnexpectedValueException('Version property not found for key "' . $key . '"'); } $completeVersions = explode('.', $properties['Version'], 2); if (!isset($properties['MajorVer']) || '#MAJORVER#' === $properties['MajorVer']) { $properties['MajorVer'] = (string) $completeVersions[0]; } elseif ($properties['MajorVer'] !== (string) $completeVersions[0]) { throw new \UnexpectedValueException('MajorVersion from properties does not match with Version for key "' . $key . '", "' . $properties['MajorVer'] . '" was defined, "' . (string) $completeVersions[0] . '" was expected'); } if (isset($completeVersions[1])) { $minorVersion = (string) $completeVersions[1]; } else { $minorVersion = '0'; } if (!isset($properties['MinorVer']) || '#MINORVER#' === $properties['MinorVer']) { $properties['MinorVer'] = $minorVersion; } elseif ($properties['MinorVer'] !== $minorVersion) { throw new \UnexpectedValueException('MinorVersion from properties does not match with Version for key "' . $key . '", "' . $properties['MinorVer'] . '" was defined, "' . $minorVersion . '" was expected'); } $allDivisions[$key] = $properties; } return $allDivisions; }
/** * Entry point for generating builds for a specified version * * @param string $version * @param string $resourceFolder * @param \Psr\Log\LoggerInterface $logger * @param \Browscap\Writer\WriterCollection $writerCollection * @param \Browscap\Helper\CollectionCreator $collectionCreator * * @throws \Exception */ public static function run($version, $resourceFolder, LoggerInterface $logger, WriterCollection $writerCollection, CollectionCreator $collectionCreator) { $logger->info('started creating a data collection'); $dataCollection = new DataCollection($version); $dataCollection->setLogger($logger); $collectionCreator->setLogger($logger)->setDataCollection($dataCollection); $collection = $collectionCreator->createDataCollection($resourceFolder); $logger->info('finished creating a data collection'); $logger->info('started initialisation of writers'); $expander = new Expander(); $expander->setDataCollection($collection)->setLogger($logger); $logger->info('finished initialisation of writers'); $logger->info('started output of header and version'); $comments = ['Provided courtesy of http://browscap.org/', 'Created on ' . $collection->getGenerationDate()->format('l, F j, Y \\a\\t h:i A T'), 'Keep up with the latest goings-on with the project:', 'Follow us on Twitter <https://twitter.com/browscap>, or...', 'Like us on Facebook <https://facebook.com/browscap>, or...', 'Collaborate on GitHub <https://github.com/browscap>, or...', 'Discuss on Google Groups <https://groups.google.com/forum/#!forum/browscap>.']; $writerCollection->setExpander($expander)->fileStart()->renderHeader($comments)->renderVersion($version, $collection); $logger->info('finished output of header and version'); $output = []; $logger->info('started output of divisions'); $division = $collection->getDefaultProperties(); $logger->info('handle division ' . $division->getName()); $writerCollection->renderAllDivisionsHeader($collection)->renderDivisionHeader($division->getName()); $ua = $division->getUserAgents(); $sections = [$ua[0]['userAgent'] => $ua[0]['properties']]; foreach (array_keys($sections) as $sectionName) { $section = $sections[$sectionName]; $writerCollection->setSilent($division)->renderSectionHeader($sectionName)->renderSectionBody($section, $collection, $sections, $sectionName)->renderSectionFooter($sectionName); } $writerCollection->renderDivisionFooter(); foreach ($collection->getDivisions() as $division) { /** @var \Browscap\Data\Division $division */ // run checks on division before expanding versions because the checked properties do not change between // versions $sections = $expander->expand($division, $division->getName()); $logger->info('checking division ' . $division->getName()); foreach (array_keys($sections) as $sectionName) { $section = $sections[$sectionName]; $collection->checkProperty($sectionName, $section); } $writerCollection->setSilent($division); $versions = $division->getVersions(); foreach ($versions as $version) { list($majorVer, $minorVer) = $expander->getVersionParts($version); $divisionName = $expander->parseProperty($division->getName(), $majorVer, $minorVer); $logger->info('handle division ' . $divisionName); $encodedSections = json_encode($sections); $encodedSections = $expander->parseProperty($encodedSections, $majorVer, $minorVer); $sectionsWithVersion = json_decode($encodedSections, true); $firstElement = current($sectionsWithVersion); $writerCollection->renderDivisionHeader($divisionName, $firstElement['Parent']); foreach (array_keys($sectionsWithVersion) as $sectionName) { if (array_key_exists($sectionName, $output)) { $logger->error('tried to add section "' . $sectionName . '" more than once -> skipped'); continue; } $section = $sectionsWithVersion[$sectionName]; $writerCollection->setSilentSection($section); $writerCollection->renderSectionHeader($sectionName)->renderSectionBody($section, $collection, $sectionsWithVersion, $sectionName)->renderSectionFooter($sectionName); $output[$sectionName] = $sectionName; } $writerCollection->renderDivisionFooter(); unset($divisionName, $majorVer, $minorVer); } } $division = $collection->getDefaultBrowser(); $logger->info('handle division ' . $division->getName()); $writerCollection->renderDivisionHeader($division->getName()); $ua = $division->getUserAgents(); $sections = [$ua[0]['userAgent'] => array_merge(['Parent' => 'DefaultProperties'], $ua[0]['properties'])]; foreach (array_keys($sections) as $sectionName) { $section = $sections[$sectionName]; $writerCollection->setSilent($division)->renderSectionHeader($sectionName)->renderSectionBody($section, $collection, $sections, $sectionName)->renderSectionFooter($sectionName); } $writerCollection->renderDivisionFooter()->renderAllDivisionsFooter(); $logger->info('finished output of divisions'); $logger->info('started closing writers'); $writerCollection->fileEnd()->close(); $logger->info('finished closing writers'); }
/** * renders the version information * * @param string $version * @param \Browscap\Data\DataCollection $collection * * @return \Browscap\Writer\WriterCollection */ public function renderVersion($version, DataCollection $collection) { foreach ($this->writers as $writer) { $writer->renderVersion(array('version' => $version, 'released' => $collection->getGenerationDate()->format('r'), 'format' => $writer->getFormatter()->getType(), 'type' => $writer->getFilter()->getType())); } return $this; }
/** * renders all found useragents into a string * * @param string[] $section * @param \Browscap\Data\DataCollection $collection * @param array[] $sections * @param string $sectionName * * @throws \InvalidArgumentException * @return CsvWriter */ public function renderSectionBody(array $section, DataCollection $collection, array $sections = [], $sectionName = '') { if ($this->isSilent()) { return $this; } $division = $collection->getDefaultProperties(); $ua = $division->getUserAgents(); $defaultproperties = $ua[0]['properties']; $properties = array_merge(['PropertyName', 'MasterParent', 'LiteMode', 'Parent'], array_keys($defaultproperties)); $values = []; $section['PropertyName'] = $sectionName; $section['MasterParent'] = $this->detectMasterParent($sectionName, $section); if (in_array($sectionName, ['DefaultProperties', '*'])) { $section['LiteMode'] = 'true'; } else { $section['LiteMode'] = !isset($section['lite']) || !$section['lite'] ? 'false' : 'true'; } foreach ($properties as $property) { if (!isset($this->outputProperties[$property])) { $this->outputProperties[$property] = $this->getFilter()->isOutputProperty($property, $this); } if (!$this->outputProperties[$property]) { continue; } if (isset($section[$property])) { $value = $section[$property]; } else { $value = ''; } $values[] = $this->getFormatter()->formatPropertyValue($value, $property); } fputs($this->file, implode(',', $values) . PHP_EOL); return $this; }
/** * tests if no error is raised if all went well * * @group data * @group sourcetest */ public function testCheckPropertyOk() { $this->object->setLogger($this->logger); $properties = array('Version' => 'abc', 'Parent' => '123', 'Device_Type' => 'Desktop', 'isTablet' => false, 'isMobileDevice' => false); self::assertTrue($this->object->checkProperty('test', $properties)); }