Index: tests/t3lib/matchcondition/t3lib_matchcondition_frontendTest.php =================================================================== --- tests/t3lib/matchcondition/t3lib_matchcondition_frontendTest.php (révision 8932) +++ tests/t3lib/matchcondition/t3lib_matchcondition_frontendTest.php (copie de travail) @@ -620,5 +620,37 @@ '[globalString = ' . $this->testGlobalNamespace . '|second|third = testThird]' )); } + + /** + * Tests whether extension comparison to a specific version matches. + * @test + */ + public function extConditionMatchVersion() { + $this->assertTrue($this->matchCondition->match('[ext=phpunit:version > 3.4.11]')); + } + + /** + * Tests whether extension comparison to a specific version does not match. + * @test + */ + public function extConditionMatchNotVersion() { + $this->assertFalse($this->matchCondition->match('[ext=phpunit:version = 3.4.11]')); + } + + /** + * Tests whether extension comparison to multiple version matches. + * @test + */ + public function extConditionMatchSomeVersions() { + $this->assertTrue($this->matchCondition->match('[ext=phpunit:version = 3.4.11] || [ext=phpunit:version = 3.4.12] || [ext=phpunit:version = 3.4.13] || [ext=phpunit:version = 3.4.14]')); + } + + /** + * Tests whether extension comparison to not match multiple versions. + * @test + */ + public function extConditionMatchNotSomeVersions() { + $this->assertFalse($this->matchCondition->match('[ext=phpunit:version = 3.3.11] || [ext=phpunit:version = 3.3.12] || [ext=phpunit:version = 3.3.13] || [ext=phpunit:version = 3.3.14]')); + } } ?> \ No newline at end of file Index: t3lib/class.t3lib_extmgm.php =================================================================== --- t3lib/class.t3lib_extmgm.php (révision 8932) +++ t3lib/class.t3lib_extmgm.php (copie de travail) @@ -231,6 +231,177 @@ } /** + * Returns the full version information string or + * a modification of it, if the modification parameter is provided + * + * @param string version code in the format "x.x.x" + * @param string version modification: "", "int", "main", "sub", "developer" + * @return string or boolean: version string or FALSE if something went wrong + * @see renderVersion() + */ + static public function getVersionInfo($version, $modification) { + $result = FALSE; + $versionInfo = self::renderVersion($version); + if ($modification == '' && isset($versionInfo['version'])) { + $result = $versionInfo['version']; + } elseif (isset($versionInfo['version_' . $modification])) { + $result = $versionInfo['version_' . $modification]; + } + return $result; + } + + /** + * Evaluates differences in version numbers with three parts, x.x.x. Returns TRUE if $v1 is greater than $v2 + * + * @param string Version number 1 + * @param string Version number 2 + * @param string comparator string for the version compare + * @param integer Tolerance factor. For instance, set to 1000 to ignore difference in developer-version (third part) + * @return boolean True if version 1 is greater than version 2 + */ + static public function getVersionDifference($version1, $version2, $comparator = '', $tolerance = 1) { + $result = FALSE; + $leftValue = floor(self::getVersionInfo($version1, 'int') / $tolerance); + $rightValue = floor(self::getVersionInfo($version2, 'int') / $tolerance); + if (!$comparator) { + $comparator = '>'; + } + $result = self::testNumber($comparator . $rightValue, $leftValue); + return $result; + } + + /** + * Evaluates a $leftValue based on an operator: "<", ">", "<=", ">=", "!=" or "=" + * + * @param string $test: The value to compare with on the form [operator][number]. Eg. "< 123" + * @param integer $leftValue: The value on the left side + * @return boolean If $value is "50" and $test is "< 123" then it will return TRUE. + */ + static public function testNumber($test, $leftValue) { + $test = trim($test); + + $result = FALSE; + if (preg_match('/^(!?=+|<=?|>=?)\s*([^\s]*)\s*$/', $test, $matches)) { + $operator = $matches[1]; + $rightValue = $matches[2]; + + switch ($operator) { + case '>=': + $result = ($leftValue >= doubleval($rightValue)); + break; + case '<=': + $result = ($leftValue <= doubleval($rightValue)); + break; + case '!=': + $result = ($leftValue != doubleval($rightValue)); + break; + case '<': + $result = ($leftValue < doubleval($rightValue)); + break; + case '>': + $result = ($leftValue > doubleval($rightValue)); + break; + default: + // nothing valid found except '=', use '=' + $result = ($leftValue == trim($rightValue)); + } + } + + return $result; + } + + /** + * Parses the version number x.x.x and returns an array with the various parts. + * + * @param string version code in the format "x.x.x" + * @param string increase version part: "main", "sub", "dev" + * @return array: + version ... version number string + version_int ... version number integer + version_main ... highest version number + version_sub ... sublevel number + version_developer ... developer number + */ + static public function renderVersion($version, $raise = '') { + $parts = t3lib_div::intExplode('.', $version . '..'); + $parts[0] = t3lib_div::intInRange($parts[0], 0, 999); + $parts[1] = t3lib_div::intInRange($parts[1], 0, 999); + $parts[2] = t3lib_div::intInRange($parts[2], 0, 999); + + switch((string)$raise) { + case 'main': + $parts[0]++; + $parts[1] = 0; + $parts[2] = 0; + break; + case 'sub': + $parts[1]++; + $parts[2] = 0; + break; + case 'dev': + $parts[2]++; + break; + } + + $result = array(); + $result['version'] = $parts[0] . '.' . $parts[1] . '.' . $parts[2]; + $result['version_int'] = intval($parts[0] * 1000000 + $parts[1] * 1000 + $parts[2]); + $result['version_main'] = $parts[0]; + $result['version_sub'] = $parts[1]; + $result['version_developer'] = $parts[2]; + + return $result; + } + + /** + * Gets information for an extension, eg. version and most-recently-edited-script + * + * @param string Extension key + * @return array / string Information array if successfull + * error text if an error occured + */ + static public function getExtensionInfo($key) { + + if (!is_string($key) || empty($key)) { + throw new InvalidArgumentException('Extension key must be a non-empty string.'); + } + if (!self::isLoaded($key)) { + return 'Error: Extension ' . $key . ' has not been installed. (t3lib_extMgm::getExtensionInfo)'; + } + + $result = ''; + $path = self::extPath($key); + $file = $path . '/ext_emconf.php'; + if (@is_file($file)) { + $_EXTKEY = $key; + $EM_CONF = array(); + include($file); + + $info = array(); + // Info from emconf: + $info['title'] = $EM_CONF[$key]['title']; + $info['author'] = $EM_CONF[$key]['author']; + $info['author_email'] = $EM_CONF[$key]['author_email']; + $info['author_company'] = $EM_CONF[$key]['author_company']; + $info['version'] = $EM_CONF[$key]['version']; + $info['CGLcompliance'] = $EM_CONF[$key]['CGLcompliance']; + $info['CGLcompliance_note'] = $EM_CONF[$key]['CGLcompliance_note']; + if (is_array($EM_CONF[$key]['constraints']) && is_array($EM_CONF[$key]['constraints']['depends'])) { + $info['TYPO3_version'] = $EM_CONF[$key]['constraints']['depends']['typo3']; + } else { + $info['TYPO3_version'] = $EM_CONF[$key]['TYPO3_version']; + } + $filesHash = unserialize($EM_CONF[$key]['_md5_values_when_last_written']); + $info['manual'] = @is_file($path . '/doc/manual.sxw'); + $result = $info; + } else { + $result = 'ERROR: No emconf.php file: ' . $file; + } + + return $result; + } + + /** * Clears the extension key map. * * @return void Index: t3lib/matchcondition/class.t3lib_matchcondition_abstract.php =================================================================== --- t3lib/matchcondition/class.t3lib_matchcondition_abstract.php (révision 8932) +++ t3lib/matchcondition/class.t3lib_matchcondition_abstract.php (copie de travail) @@ -36,6 +36,8 @@ * @package TYPO3 * @subpackage t3lib */ + + abstract class t3lib_matchCondition_abstract { /** * Id of the current page. @@ -201,12 +203,88 @@ } /** + * Evaluates a TypoScript condition for an extension with only one version number given. + * No commas "," are allowed in the current value. + * + * @param string the extension key + * @param string attribute to check. Only 'version' is supported + * @param string single value from the condition setup line + * @return mixed Returns TRUE or FALSE based on the evaluation + */ + static protected function evaluateConditionExtensionSingle($extensionKey, $attribute, $currentValue) { + $result = FALSE; + $infoArray = t3lib_extMgm::getExtensionInfo($extensionKey); + + if ( + is_array($infoArray) && + isset($infoArray[$attribute]) + ) { + $test = $infoArray[$attribute] . $currentValue; + switch ($attribute) { + case 'version': + if (preg_match('/^\s*([^\s]*)\s*(!?=+|<=?|>=?)\s*([^\s]*)\s*$/', $test, $matches)) { + $result = t3lib_extMgm::getVersionDifference( + $matches['1'], + $matches['3'], + $matches['2'], + 1 + ); + } + break; + } + } + return $result; + } + + /** + * Evaluates a TypoScript condition for an extension where multiple version numbers can be checked. + * Commas "," are allowed in the current item value. + * + * @param string condition item from the setup + * @return mixed Returns TRUE or FALSE based on the evaluation + */ + static protected function evaluateConditionExt($value) { + // processing of the condition setup line + $values = t3lib_div::trimExplode(',', $value, TRUE); + $point = strcspn($value, '!=<>'); + $part = substr($value, 0, $point); + $values['0'] = substr($value, $point); + $keyArray = explode(':', $part); + $extensionKey = $keyArray['0']; + $attribute = trim($keyArray['1']); + + foreach($values as $currentValue) { + if (strlen($currentValue) && strlen($extensionKey)) { + $currentValue = trim($currentValue); + $bIsLoaded = t3lib_extMgm::isLoaded($extensionKey); + + if (!strlen($attribute) && $bIsLoaded || ($attribute == 'active' && intval($bIsLoaded) == $currentValue)) { + $result = TRUE; + } else { + $result = self::evaluateConditionExtensionSingle($extensionKey, $attribute, $currentValue); + } + } + if ($result == TRUE) { + break; + } + } + return $result; + } + + /** * Evaluates a TypoScript condition given as input, eg. "[browser=net][...(other conditions)...]" * - * @param string The condition to match against its criterias. + * @param string The condition type key: + * 'browser', 'version', 'system', 'device', + *' 'useragent','language', 'IP', 'hostname', 'hour', 'minute', + * 'month', 'year', 'dayofweek', 'dayofmonth', 'dayofyear', + * 'compatVersion', 'loginUser', 'globalVar', 'globalString', + * 'userFunc', 'ext' + * @param string The condition item from the setup * @return mixed Returns true or false based on the evaluation */ protected function evaluateConditionCommon($key, $value) { + $result = FALSE; if (t3lib_div::inList('browser,version,system,useragent', strtolower($key))) { $browserInfo = $this->getBrowserInfo(t3lib_div::getIndpEnv('HTTP_USER_AGENT')); } @@ -393,9 +471,12 @@ return true; } break; + case 'ext': + $result = self::evaluateConditionExt($value); + break; } - return NULL; + return $result; } protected function getVariableCommon(array $vars) {