diff --git a/library/Director/PropertyModifier/PropertyModifierParseURL.php b/library/Director/PropertyModifier/PropertyModifierParseURL.php new file mode 100644 index 00000000..ce7c81be --- /dev/null +++ b/library/Director/PropertyModifier/PropertyModifierParseURL.php @@ -0,0 +1,81 @@ + PHP_URL_SCHEME, + 'host' => PHP_URL_HOST, + 'port' => PHP_URL_PORT, + 'path' => PHP_URL_PATH, + 'query' => PHP_URL_QUERY, + 'fragment' => PHP_URL_FRAGMENT, + ]; + + public static function addSettingsFormFields(QuickForm $form) + { + $form->addElement('select', 'url_component', [ + 'label' => $form->translate('URL component'), + 'description' => $form->translate('URL component'), + 'multiOptions' => $form->optionalEnum(static::enumComponents()), + 'required' => true, + ]); + + $form->addElement('select', 'on_failure', [ + 'label' => $form->translate('On failure'), + 'description' => $form->translate( + 'What should we do if the URL could not get parsed or component not found?' + ), + 'multiOptions' => $form->optionalEnum([ + 'null' => $form->translate('Set no value (null)'), + 'keep' => $form->translate('Keep the property as is'), + 'fail' => $form->translate('Let the whole import run fail'), + ]), + 'required' => true, + ]); + } + + protected static function enumComponents() + { + $components = array_keys(self::$components); + return array_combine($components, $components); + } + + public function getName() + { + return 'Parse a URL and return its components'; + } + + public function transform($value) + { + $component = self::$components[$this->getSetting('url_component')]; + $response = parse_url($value, $component); + + // if component not found $response will be null, false if seriously malformed URL + if ($response === null || $response === false) { + switch ($this->getSetting('on_failure')) { + case 'null': + return null; + case 'keep': + return $value; + case 'fail': + default: + throw new InvalidPropertyException( + 'Parsing URL "%s" failed.', + $value + ); + } + } + + return $response; + } +} diff --git a/run.php b/run.php index 9a77010b..7e762545 100644 --- a/run.php +++ b/run.php @@ -53,6 +53,7 @@ $this->provideHook('director/PropertyModifier', $prefix . 'PropertyModifier\\Pro $this->provideHook('director/PropertyModifier', $prefix . 'PropertyModifier\\PropertyModifierUpperCaseFirst'); $this->provideHook('director/PropertyModifier', $prefix . 'PropertyModifier\\PropertyModifierRejectOrSelect'); $this->provideHook('director/PropertyModifier', $prefix . 'PropertyModifier\\PropertyModifierArrayElementByPosition'); +$this->provideHook('director/PropertyModifier', $prefix . 'PropertyModifier\\PropertyModifierParseURL'); $this->provideHook('director/Job', $prefix . 'Job\\HousekeepingJob'); $this->provideHook('director/Job', $prefix . 'Job\\ConfigJob'); diff --git a/test/php/library/Director/PropertyModifier/PropertyModifierParseURLTest.php b/test/php/library/Director/PropertyModifier/PropertyModifierParseURLTest.php new file mode 100644 index 00000000..53c303fe --- /dev/null +++ b/test/php/library/Director/PropertyModifier/PropertyModifierParseURLTest.php @@ -0,0 +1,147 @@ +assertFalse($modifier->hasArraySupport()); + } + + public function testEmptyPropertyReturnsNullOnfailureNull() + { + $modifier = new PropertyModifierParseURL(); + $modifier->setSettings([ + 'url_component' => 'query', + 'on_failure' => 'null', + ]); + + $this->assertNull($modifier->transform('')); + } + + public function testMissingComponentReturnsNullOnfailureNull() + { + $modifier = new PropertyModifierParseURL(); + $modifier->setSettings([ + 'url_component' => 'query', + 'on_failure' => 'null', + ]); + + $this->assertNull($modifier->transform('https://www.icinga.org/path/')); + } + + public function testMissingComponentReturnsPropertyOnfailureKeep() + { + $modifier = new PropertyModifierParseURL(); + $modifier->setSettings([ + 'url_component' => 'query', + 'on_failure' => 'keep', + ]); + + $this->assertEquals('http://www.icinga.org/path/', $modifier->transform('http://www.icinga.org/path/')); + } + + /** + * @expectedException Icinga\Exception\InvalidPropertyException + */ + public function testMissingComponentThrowsExceptionOnfailureFail() + { + $modifier = new PropertyModifierParseURL(); + $modifier->setSettings([ + 'url_component' => 'query', + 'on_failure' => 'fail', + ]); + + $modifier->transform('http://www.icinga.org/path/'); + } + + + public function testInvalidUrlReturnsNullOnfailureNull() + { + $modifier = new PropertyModifierParseURL(); + $modifier->setSettings([ + 'url_component' => 'host', + 'on_failure' => 'null', + ]); + + $this->assertNull($modifier->transform(self::$invalidurl)); + } + + public function testInvalidUrlReturnsItselfOnfailureKeep() + { + $modifier = new PropertyModifierParseURL(); + $modifier->setSettings([ + 'url_component' => 'host', + 'on_failure' => 'keep', + ]); + + $this->assertEquals(self::$invalidurl, $modifier->transform(self::$invalidurl)); + } + + /** + * @expectedException Icinga\Exception\InvalidPropertyException + */ + public function testInvalidUrlThrowsExceptionOnfailureFail() + { + $modifier = new PropertyModifierParseURL(); + $modifier->setSettings([ + 'url_component' => 'host', + 'on_failure' => 'fail', + ]); + + $modifier->transform(self::$invalidurl); + } + + + /** + * @dataProvider dataURLcomponentProvider + */ + public function testSuccessfullyParse($component, $result) + { + $modifier = new PropertyModifierParseURL(); + $modifier->setSettings([ + 'url_component' => $component, + 'on_failure' => 'null', + ]); + + $this->assertEquals($result, $modifier->transform(self::$validurl)); + } + public function dataURLcomponentProvider() + { + return [ + 'scheme' => [ + 'scheme', + 'https', + ], + 'host' => [ + 'host', + 'www.icinga.org', + ], + 'port' => [ + 'port', + '', + ], + 'path' => [ + 'path', + '/path/file.html', + ], + 'query' => [ + 'query', + 'foo=bar', + ], + 'fragment' => [ + 'fragment', + 'section', + ], + ]; + } +}