diff --git a/.gitignore b/.gitignore index ca17bd2..3e2c495 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,4 @@ .idea .phpunit.cache/ .phpunit.result.cache -.composer.lock +composer.lock diff --git a/README.md b/README.md index 7ae8aa7..90eb14d 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ Helper package used for the validation of social links. ## Requirements -This project requires PHP 8.1 or higher with the `mbstring` extension installed. +This project requires PHP 8.2 or higher with the `mbstring` extension installed. ## Installation @@ -21,7 +21,7 @@ composer require dealroom/socials-helpers ## Usage -The `Factory` class provides a simple wrapper for the validation functionality, for example to get normalized URL: +The `Factory` class provides a simple wrapper for the validation functionality, for example, to get normalized URL: ```php use Dealroom\SocialsHelpers\Factory; @@ -47,9 +47,54 @@ echo $data; // "dealroom" ``` +## Supported Platforms + +The following platforms are supported by default: + +- Apple Music +- Facebook +- Instagram +- LinkedIn +- Twitter +- YouTube +- TikTok +- SoundCloud +- X +- Spotify + +### Registering new platforms + +To register a new normalizer, you need to create a new class that implements +the `NormalizerInterface` interface and add it to the `Factory` class. + +```php +use Dealroom\SocialsHelpers\Normalizers\NormalizerInterface; + +class CustomNormalizer implements NormalizerInterface +{ + // Implement the interface methods +} +``` + +Then add it to the `Factory` class + +```php +use Dealroom\SocialsHelpers\Normalizers\Factory; + +Factory::addNormalizer(CustomNormalizer::class); +``` + +And now, you can use it + +```php +use Dealroom\SocialsHelpers\Factory; + +$data = Factory::parseUrl('https://custom.com/Dealroom', [Parser::PLATFORM_CUSTOM])->getNormalizedUrl(); +``` + ## Testing -PHPUnit is used for testing, just run: +PHPUnit is used for testing, run: ```bash ./vendor/bin/phpunit @@ -58,4 +103,5 @@ PHPUnit is used for testing, just run: ## Releases and CI/CD The release is done automatically using GitHub actions on every push to the `main` branch. -After the release is done, a new tag is created and pushed to GitHub which triggers a new release in [packagist](https://packagist.org/). +After the release is done, a new tag is created and pushed to GitHub, +which triggers a new release in [packagist](https://packagist.org/). diff --git a/composer.json b/composer.json index cd3ce6a..c66a5fa 100644 --- a/composer.json +++ b/composer.json @@ -1,15 +1,15 @@ { "name": "dealroom/socials-helpers", - "description": "Helper package used for the validation of social links", + "description": "Helper package used for the validation and normalization of social media links", "type": "library", "license": "MIT", "keywords": ["social", "linkedin", "facebook", "twitter"], "require": { - "php": ">=8.1", + "php": ">=8.2", "ext-mbstring": "*" }, "require-dev": { - "phpunit/phpunit": "^10.3" + "phpunit/phpunit": "^11.2" }, "scripts": { "test": "vendor/bin/phpunit" diff --git a/src/Factory.php b/src/Factory.php index 7a00061..c5bfaa1 100644 --- a/src/Factory.php +++ b/src/Factory.php @@ -6,13 +6,8 @@ class Factory { - /** - * @param string $url - * @param array $allowedTypes - * @return Result - */ - public static function parseUrl(string $url, array $allowedTypes = []): Result + public static function parseUrl(string $url, array $allowedPlatforms = []): Result { - return (new Parser())->parseUrl($url, $allowedTypes); + return (new Parser())->parseUrl($url, $allowedPlatforms); } } diff --git a/src/Normalizers/AbstractNormalizer.php b/src/Normalizers/AbstractNormalizer.php index 7313aaa..6f2fab9 100644 --- a/src/Normalizers/AbstractNormalizer.php +++ b/src/Normalizers/AbstractNormalizer.php @@ -4,17 +4,61 @@ namespace Dealroom\SocialsHelpers\Normalizers; +use Dealroom\SocialsHelpers\Exceptions\NormalizeException; use Dealroom\SocialsHelpers\Utils; abstract class AbstractNormalizer implements NormalizerInterface { + protected string $pattern; + protected string $normalizedUrl; + protected int|array $idPosition; + + protected array $cleanUrlSettings = ['forceHTTPS' => true, 'forceLowerCase' => true]; + public function normalize(string $url): string { - return Utils::cleanUrl($url); + return sprintf($this->normalizedUrl, $this->normalizeToId($url)); + } + + public function normalizeToId(string $url, array $settings = []): string + { + $settings = array_merge($this->cleanUrlSettings, $settings); + + $url = Utils::cleanUrl($url, $settings); + + $matches = $this->match($url); + + if (is_array($this->idPosition)) { + foreach ($this->idPosition as $position) { + if (isset($matches[$position])) { + return $matches[$position]; + } + } + return $matches[$this->idPosition[0] ?? 0]; + } + + return $matches[$this->idPosition]; + } + + public function getPattern(): string + { + return $this->pattern; } - public function normalizeToId(string $url): string + protected function match(string $url): array { - return ''; + $result = preg_match( + $this->pattern, + rawurldecode($url), + $matches + ); + + if (!$result) { + throw new NormalizeException( + sprintf("%s pattern didn't match for '%s'", static::getPlatform(), $url) + ); + } + + return $matches; } } diff --git a/src/Normalizers/AppleMusicNormalizer.php b/src/Normalizers/AppleMusicNormalizer.php new file mode 100644 index 0000000..e6c67b1 --- /dev/null +++ b/src/Normalizers/AppleMusicNormalizer.php @@ -0,0 +1,21 @@ +getMatches($matches); - - return $matches[0]; - } else { - // phpcs:ignore Generic.Files.LineLength.TooLong - $result = preg_match('/(?:(?:http|https):\/\/)?(www\.|m\.|mobile\.|business\.|web\.|p-upload\.|[a-z]{2}-[a-z]{2}\.)?facebook.com\/pages\/[\w\-+.%,()]+\/[\w\-]+\/\d+/', $url, $matches); - if ($result) { - $matches = $this->getMatches($matches); - - return $matches[0]; - } - - throw new NormalizeException(); - } - } - - // phpcs:ignore Generic.Files.LineLength.TooLong - $result = preg_match('/(?:(?:http|https):\/\/)?(www\.|m\.|mobile\.|business\.|web\.|p-upload\.|[a-z]{2}-[a-z]{2}\.)?facebook.com\/[\w\-+.%,()]+/', $url, $matches); - if ($result) { - $matches = $this->getMatches($matches); - - return rtrim($matches[0], '/'); - } - - throw new NormalizeException(); + return 'facebook_page'; } - private function getMatches(array $matches): array - { - if (isset($matches[1])) { - $matches[0] = str_replace($matches[1], '', $matches[0]); - } - - if (!isset($matches[0])) { - throw new NormalizeException(); - } + // phpcs:disable Generic.Files.LineLength.TooLong + protected string $pattern = '/https?:\/\/(?:www\.|m\.|mobile\.|business\.|web\.|p-upload\.|[a-z]{2}-[a-z]{2}\.)?(?:facebook|fb)\.com\/(?!home\.php)(?:sharer\/|sharer.php|share.php|people\/_\/|profile\.php|pages\/)?(?:(?:([\pL][\pL0-9_\-\+\.\%]+)\/?)+)(\d+)?\/?/u'; + // phpcs:enable Generic.Files.LineLength.TooLong - if (str_starts_with($matches[0], 'http://')) { - $matches[0] = str_replace('http://', 'https://', $matches[0]); - } - if (!str_contains($matches[0], 'www.facebook.com')) { - $matches[0] = str_replace('facebook.com', 'www.facebook.com', $matches[0]); - } + protected string $normalizedUrl = 'https://www.facebook.com/%s'; - return $matches; - } + protected array|int $idPosition = [2, 1]; } diff --git a/src/Normalizers/FacebookProfileNormalizer.php b/src/Normalizers/FacebookProfileNormalizer.php index 977daf5..0ddc7e1 100644 --- a/src/Normalizers/FacebookProfileNormalizer.php +++ b/src/Normalizers/FacebookProfileNormalizer.php @@ -4,28 +4,16 @@ namespace Dealroom\SocialsHelpers\Normalizers; -use Dealroom\SocialsHelpers\Parser; - class FacebookProfileNormalizer extends AbstractNormalizer { - public function normalize(string $url): string + public static function getPlatform(): string { - $matches = $this->match($url); - - return 'https://www.facebook.com/' . $matches[4] . $matches[5]; + return 'facebook_profile'; } - public function normalizeToId(string $url): string - { - $matches = $this->match($url); + protected string $pattern = '/http(s)?:\/\/(www\.)?(facebook|fb)\.com\/(people\/_\/|profile\.php\?id=)(\d+)\/?/'; - return $matches[5]; - } + protected string $normalizedUrl = 'https://www.facebook.com/profile.php?id=%s'; - private function match(string $url): array - { - preg_match(Parser::FACEBOOK_PROFILE_URL_REGEX, $url, $matches); - - return $matches; - } + protected array|int $idPosition = 5; } diff --git a/src/Normalizers/Factory.php b/src/Normalizers/Factory.php index baa12bb..43c3d01 100644 --- a/src/Normalizers/Factory.php +++ b/src/Normalizers/Factory.php @@ -5,32 +5,44 @@ namespace Dealroom\SocialsHelpers\Normalizers; use Dealroom\SocialsHelpers\Exceptions\NormalizeException; -use Dealroom\SocialsHelpers\Parser; class Factory { - public static array $normalizers = [ - Parser::PLATFORM_FACEBOOK_PAGE => FacebookPageNormalizer::class, - Parser::PLATFORM_FACEBOOK_PROFILE => FacebookProfileNormalizer::class, - Parser::PLATFORM_TWITTER => TwitterNormalizer::class, - Parser::PLATFORM_X => XNormalizer::class, - Parser::PLATFORM_LINKEDIN_COMPANY => LinkedinCompanyNormalizer::class, - Parser::PLATFORM_LINKEDIN_SHOWCASE => LinkedinShowcaseNormalizer::class, - Parser::PLATFORM_LINKEDIN_SCHOOL => LinkedinSchoolNormalizer::class, - Parser::PLATFORM_LINKEDIN_PROFILE => LinkedinProfileNormalizer::class, + private static array $normalizers = [ + AppleMusicNormalizer::class, + FacebookPageNormalizer::class, + FacebookProfileNormalizer::class, + InstagramNormalizer::class, + LinkedinCompanyNormalizer::class, + LinkedinProfileNormalizer::class, + LinkedinSchoolNormalizer::class, + LinkedinShowcaseNormalizer::class, + SoundcloudNormalizer::class, + SpotifyArtistNormalizer::class, + TikTokNormalizer::class, + TwitterNormalizer::class, + XNormalizer::class, + YoutubeNormalizer::class, ]; - /** - * @param string $platform - * - * @return NormalizerInterface - */ public static function getForPlatform(string $platform): NormalizerInterface { - if (!isset(self::$normalizers[$platform])) { - throw new NormalizeException(sprintf('No normalizer found for platform %s', $platform)); + foreach (self::$normalizers as $normalizer) { + if ($normalizer::getPlatform() === $platform) { + return new $normalizer(); + } } - return new self::$normalizers[$platform](); + throw new NormalizeException(sprintf('No normalizer found for platform %s', $platform)); + } + + public static function addNormalizer(NormalizerInterface $normalizer): void + { + self::$normalizers[] = $normalizer::class; + } + + public static function getNormalizers(): array + { + return self::$normalizers; } } diff --git a/src/Normalizers/InstagramNormalizer.php b/src/Normalizers/InstagramNormalizer.php new file mode 100644 index 0000000..9b6ccd8 --- /dev/null +++ b/src/Normalizers/InstagramNormalizer.php @@ -0,0 +1,19 @@ +match($url); - - return 'https://www.linkedin.com/company/' . $matches[3] . '/'; - } - - public function normalizeToId(string $url): string + public static function getPlatform(): string { - $matches = $this->match($url); - - return $matches[3]; + return 'linkedin_company'; } - private function match(string $url): array - { - $result = preg_match(Parser::LINKEDIN_COMPANY_REGEX, rawurldecode($url), $matches); + protected string $pattern = '/http(s)?:\/\/(www\.)?linkedin\.com\/company\/?([\p{L}\d&\'.\-–_®]+)\/?/u'; - if (!$result) { - throw new NormalizeException( - sprintf('Linkedin company pattern didn\'t match for %s', $url) - ); - } + protected string $normalizedUrl = 'https://www.linkedin.com/company/%s/'; - return $matches; - } + protected array|int $idPosition = 3; } diff --git a/src/Normalizers/LinkedinProfileNormalizer.php b/src/Normalizers/LinkedinProfileNormalizer.php index 4d10d85..beaf6c4 100644 --- a/src/Normalizers/LinkedinProfileNormalizer.php +++ b/src/Normalizers/LinkedinProfileNormalizer.php @@ -4,39 +4,16 @@ namespace Dealroom\SocialsHelpers\Normalizers; -use Dealroom\SocialsHelpers\Exceptions\NormalizeException; -use Dealroom\SocialsHelpers\Parser; - class LinkedinProfileNormalizer extends AbstractNormalizer { - public function normalize(string $url): string - { - $matches = $this->match($url); - - return 'https://www.linkedin.com/in/' . $matches[1] . '/'; - } - - public function normalizeToId(string $url): string + public static function getPlatform(): string { - $matches = $this->match($url); - - return $matches[1]; + return 'linkedin_profile'; } - private function match(string $url): array - { - $result = preg_match( - Parser::LINKEDIN_PROFILE_REGEX, - rawurldecode($url), - $matches - ); + protected string $pattern = '/(?:https?:)?\/\/(?:[\w]+\.)?linkedin\.com\/in\/([\w\-\_À-ÿ%]+)\/?/u'; - if (!$result) { - throw new NormalizeException( - sprintf('Linkedin profile pattern didn\'t match for %s', $url) - ); - } + protected string $normalizedUrl = 'https://www.linkedin.com/in/%s/'; - return $matches; - } + protected array|int $idPosition = 1; } diff --git a/src/Normalizers/LinkedinSchoolNormalizer.php b/src/Normalizers/LinkedinSchoolNormalizer.php index b3e9708..ffa7a7d 100644 --- a/src/Normalizers/LinkedinSchoolNormalizer.php +++ b/src/Normalizers/LinkedinSchoolNormalizer.php @@ -4,39 +4,16 @@ namespace Dealroom\SocialsHelpers\Normalizers; -use Dealroom\SocialsHelpers\Exceptions\NormalizeException; -use Dealroom\SocialsHelpers\Parser; - class LinkedinSchoolNormalizer extends AbstractNormalizer { - public function normalize(string $url): string - { - $matches = $this->match($url); - - return 'https://www.linkedin.com/school/' . $matches[3] . '/'; - } - - public function normalizeToId(string $url): string + public static function getPlatform(): string { - $matches = $this->match($url); - - return $matches[3]; + return 'linkedin_school'; } - private function match(string $url): array - { - $result = preg_match( - Parser::LINKEDIN_SCHOOL_REGEX, - rawurldecode($url), - $matches - ); + protected string $pattern = '/http(s)?:\/\/(www\.)?linkedin\.com\/school\/?([\p{L}\d&\'.\-–_®]+)\/?/u'; - if (!$result) { - throw new NormalizeException( - sprintf('Linkedin school pattern didn\'t match for %s', $url) - ); - } + protected string $normalizedUrl = 'https://www.linkedin.com/school/%s/'; - return $matches; - } + protected array|int $idPosition = 3; } diff --git a/src/Normalizers/LinkedinShowcaseNormalizer.php b/src/Normalizers/LinkedinShowcaseNormalizer.php index 694376b..2b1eff9 100644 --- a/src/Normalizers/LinkedinShowcaseNormalizer.php +++ b/src/Normalizers/LinkedinShowcaseNormalizer.php @@ -4,39 +4,16 @@ namespace Dealroom\SocialsHelpers\Normalizers; -use Dealroom\SocialsHelpers\Exceptions\NormalizeException; -use Dealroom\SocialsHelpers\Parser; - class LinkedinShowcaseNormalizer extends AbstractNormalizer { - public function normalize(string $url): string - { - $matches = $this->match($url); - - return 'https://www.linkedin.com/showcase/' . $matches[3] . '/'; - } - - public function normalizeToId(string $url): string + public static function getPlatform(): string { - $matches = $this->match($url); - - return $matches[3]; + return 'linkedin_showcase'; } - private function match(string $url): array - { - $result = preg_match( - Parser::LINKEDIN_SHOWCASE_REGEX, - rawurldecode($url), - $matches - ); + protected string $pattern = '/http(s)?:\/\/(www\.)?linkedin\.com\/showcase\/?([\p{L}\d&\'.\-–_®]+)\/?/u'; - if (!$result) { - throw new NormalizeException( - sprintf('Linkedin showcase pattern didn\'t match for %s', $url) - ); - } + protected string $normalizedUrl = 'https://www.linkedin.com/showcase/%s/'; - return $matches; - } + protected array|int $idPosition = 3; } diff --git a/src/Normalizers/NormalizerInterface.php b/src/Normalizers/NormalizerInterface.php index 52c02cb..15ef988 100644 --- a/src/Normalizers/NormalizerInterface.php +++ b/src/Normalizers/NormalizerInterface.php @@ -4,7 +4,15 @@ interface NormalizerInterface { + /** + * Name of the platform e.g., facebook, instagram, TikTok, etc. + * Note: must be unique among all registered normalizers + */ + public static function getPlatform(): string; + public function normalize(string $url): string; - public function normalizeToId(string $url): ?string; + public function normalizeToId(string $url, array $settings = []): ?string; + + public function getPattern(): string; } diff --git a/src/Normalizers/SoundcloudNormalizer.php b/src/Normalizers/SoundcloudNormalizer.php new file mode 100644 index 0000000..45832fe --- /dev/null +++ b/src/Normalizers/SoundcloudNormalizer.php @@ -0,0 +1,19 @@ + true, 'forceLowerCase' => false]; +} diff --git a/src/Normalizers/TikTokNormalizer.php b/src/Normalizers/TikTokNormalizer.php new file mode 100644 index 0000000..03b34f3 --- /dev/null +++ b/src/Normalizers/TikTokNormalizer.php @@ -0,0 +1,19 @@ +match($url); + protected string $normalizedUrl = 'https://twitter.com/%s'; - return 'https://' . $this->getDomain() . '.com/' . $matches[4]; - } - - public function normalizeToId(string $url): string - { - $url = parent::normalize($url); - - $matches = $this->match($url); - - return $matches[4]; - } + protected array|int $idPosition = 1; - /** - * @param string $url - * - * @return array - */ - private function match(string $url): array + protected function match(string $url): array { $result = preg_match($this->getPattern(), $url, $matches); if (!$result) { throw new NormalizeException( - sprintf('%s pattern didn\'t match for %s', ucfirst($this->getDomain()), $url) + sprintf("%s pattern didn't match for %s", static::getPlatform(), $url) ); } - if ($matches[4] === 'share') { + if ($matches[1] === 'share') { throw new NormalizeException( - sprintf('%s name can not be equal to share', ucfirst($this->getDomain())) + sprintf('%s name can not be equal to share', static::getPlatform()) ); } - if (strlen($matches[4]) > 15) { + if (strlen($matches[1]) > 15) { throw new NormalizeException( - sprintf('%s name can not be longer than 15 chars: %s', ucfirst($this->getDomain()), $matches[4]) + sprintf('%s name can not be longer than 15 chars: %s', static::getPlatform(), $matches[4]) ); } diff --git a/src/Normalizers/XNormalizer.php b/src/Normalizers/XNormalizer.php index 462bb85..957c9d2 100644 --- a/src/Normalizers/XNormalizer.php +++ b/src/Normalizers/XNormalizer.php @@ -4,18 +4,14 @@ namespace Dealroom\SocialsHelpers\Normalizers; -use Dealroom\SocialsHelpers\Exceptions\NormalizeException; -use Dealroom\SocialsHelpers\Parser; - class XNormalizer extends TwitterNormalizer { - protected function getDomain(): string + public static function getPlatform(): string { return 'x'; } - protected function getPattern(): string - { - return Parser::X_URL_REGEX; - } + protected string $pattern = '/https?:\/\/(?:www\.)?x\.com\/@?(?:#!\/)?([A-z0-9_]+)\/?/'; + + protected string $normalizedUrl = 'https://x.com/%s'; } diff --git a/src/Normalizers/YoutubeNormalizer.php b/src/Normalizers/YoutubeNormalizer.php new file mode 100644 index 0000000..f1c426d --- /dev/null +++ b/src/Normalizers/YoutubeNormalizer.php @@ -0,0 +1,23 @@ + false ]; +} diff --git a/src/Parser.php b/src/Parser.php index cf71ce7..877dc32 100644 --- a/src/Parser.php +++ b/src/Parser.php @@ -6,56 +6,13 @@ use Dealroom\SocialsHelpers\Exceptions\InvalidPlatformException; use Dealroom\SocialsHelpers\Exceptions\InvalidUrlException; +use Dealroom\SocialsHelpers\Normalizers\Factory; class Parser { - public const PLATFORM_FACEBOOK_PAGE = 'facebook_page'; - public const PLATFORM_FACEBOOK_PROFILE = 'facebook_profile'; - public const PLATFORM_TWITTER = 'twitter'; - public const PLATFORM_X = 'x'; - public const PLATFORM_LINKEDIN_COMPANY = 'linkedin_company'; - public const PLATFORM_LINKEDIN_SHOWCASE = 'linkedin_showcase'; - public const PLATFORM_LINKEDIN_SCHOOL = 'linkedin_school'; - public const PLATFORM_LINKEDIN_PROFILE = 'linkedin_profile'; - - public const SOCIAL_MEDIA_PATTERNS = [ - self::PLATFORM_FACEBOOK_PAGE => self::FACEBOOK_PAGE_URL_REGEX, - self::PLATFORM_FACEBOOK_PROFILE => self::FACEBOOK_PROFILE_URL_REGEX, - self::PLATFORM_TWITTER => self::TWITTER_URL_REGEX, - self::PLATFORM_X => self::X_URL_REGEX, - self::PLATFORM_LINKEDIN_COMPANY => self::LINKEDIN_COMPANY_REGEX, - self::PLATFORM_LINKEDIN_SHOWCASE => self::LINKEDIN_SHOWCASE_REGEX, - self::PLATFORM_LINKEDIN_SCHOOL => self::LINKEDIN_SCHOOL_REGEX, - self::PLATFORM_LINKEDIN_PROFILE => self::LINKEDIN_PROFILE_REGEX, - ]; - - // phpcs:ignore Generic.Files.LineLength.TooLong - public const FACEBOOK_PAGE_URL_REGEX = '/http(s)?:\/\/(www\.|m\.|mobile\.|business\.|web\.|p-upload\.|[a-z]{2}-[a-z]{2}\.)?(facebook|fb)\.com\/(?!sharer\/)(?!sharer.php)(?!share.php)(?!people\/_\/)(?!profile\.php)(pages\/)?([\p{L}0-9_\-\.\+]+)(\/\d+)?\/?/'; - - // phpcs:ignore Generic.Files.LineLength.TooLong - public const FACEBOOK_PROFILE_URL_REGEX = '/http(s)?:\/\/(www\.)?(facebook|fb)\.com\/(people\/_\/|profile\.php\?id=)(\d+)\/?/'; - - public const TWITTER_URL_REGEX = '/http(s)?:\/\/(www\.)?twitter\.com\/@?(#!\/)?([A-z0-9_]+)\/?/'; - - public const X_URL_REGEX = '/http(s)?:\/\/(www\.)?x\.com\/@?(#!\/)?([A-z0-9_]+)\/?/'; - - public const LINKEDIN_COMPANY_REGEX = '/http(s)?:\/\/(www\.)?linkedin\.com\/company\/?([\p{L}\d&\'.\-–_®]+)\/?/u'; - - public const LINKEDIN_SHOWCASE_REGEX = '/http(s)?:\/\/(www\.)?linkedin\.com\/showcase\/?([\p{L}\d&\'.\-–_®]+)\/?/u'; - - public const LINKEDIN_SCHOOL_REGEX = '/http(s)?:\/\/(www\.)?linkedin\.com\/school\/?([\p{L}\d&\'.\-–_®]+)\/?/u'; - - public const LINKEDIN_PROFILE_REGEX = '/(?:https?:)?\/\/(?:[\w]+\.)?linkedin\.com\/in\/([\w\-\_À-ÿ%]+)\/?/u'; - - /** - * @param string $url - * @param array $allowedPlatforms - * @return Result - */ public function parseUrl(string $url, array $allowedPlatforms = []): Result { $url = Utils::cleanUrl($url); - if (!Utils::isValidUrl($url)) { throw new InvalidUrlException(sprintf('Invalid url %s', $url)); } @@ -65,19 +22,17 @@ public function parseUrl(string $url, array $allowedPlatforms = []): Result return new Result($platform, $url); } - /** - * @param string $url - * @param array $allowedTypes - * @return string - */ - private function identifyPlatform(string $url, array $allowedTypes = []): string + private function identifyPlatform(string $url, array $allowedPlatforms = []): string { - foreach (self::SOCIAL_MEDIA_PATTERNS as $platform => $pattern) { - if ($allowedTypes && !in_array($platform, $allowedTypes)) { + foreach (Factory::getNormalizers() as $normalizer) { + $platform = $normalizer::getPlatform(); + if (!empty($allowedPlatforms) && !in_array($platform, $allowedPlatforms)) { continue; } - if (preg_match($pattern, rawurldecode($url))) { - return $platform; + + $normalizerInstance = Factory::getForPlatform($platform); + if (preg_match($normalizerInstance->getPattern(), rawurldecode($url))) { + return $normalizerInstance::getPlatform(); } } diff --git a/src/Result.php b/src/Result.php index fe15e36..05c7514 100644 --- a/src/Result.php +++ b/src/Result.php @@ -15,12 +15,6 @@ class Result private string $id; private NormalizerInterface $normalizer; - /** - * Result constructor. - * - * @param string $platform - * @param string $url - */ public function __construct(string $platform, string $url) { $this->platform = $platform; @@ -30,41 +24,26 @@ public function __construct(string $platform, string $url) $this->id = $this->normalizer->normalizeToId($this->url); } - /** - * @return string - */ public function getPlatform(): string { return $this->platform; } - /** - * @return string - */ public function getUrl(): string { return $this->url; } - /** - * @return string - */ public function getNormalizedUrl(): string { return $this->normalizedUrl; } - /** - * @return string - */ public function getId(): string { return $this->id; } - /** - * @return Normalizers\NormalizerInterface - */ private function getNormalizer(): NormalizerInterface { return NormalizerFactory::getForPlatform($this->platform); diff --git a/src/Utils.php b/src/Utils.php index 7b96870..f0effd2 100644 --- a/src/Utils.php +++ b/src/Utils.php @@ -6,18 +6,25 @@ class Utils { - /** - * @param string $url - * @return string - */ - public static function cleanUrl(string $url): string + public static function cleanUrl(string $url, array $settings = []): string { - $url = mb_strtolower(trim($url)); + $settings = array_merge([ + 'forceHTTPS' => false, + 'forceLowerCase' => false, + ], $settings); + + if ($settings['forceLowerCase'] === true) { + $url = mb_strtolower(trim($url)); + } + + if ($settings['forceHTTPS'] === true && str_starts_with($url, 'http://')) { + $url = preg_replace('/^http:\/\//', 'https://', $url); + } // Clean usages of #! $url = str_replace('#!/', '/', $url); - // Clean weird double slashes // + // Clean double slashes // if (strlen($url) > 7) { while (strpos($url, '//', 7) !== false) { $url = substr_replace($url, '', strpos($url, '//', 7), 1); diff --git a/tests/NormalizerFactoryTest.php b/tests/NormalizerFactoryTest.php new file mode 100644 index 0000000..d369737 --- /dev/null +++ b/tests/NormalizerFactoryTest.php @@ -0,0 +1,70 @@ +assertInstanceOf(TwitterNormalizer::class, $twitterNormalizer); + $this->assertInstanceOf(FacebookPageNormalizer::class, $facebookPageNormalizer); + $this->assertInstanceOf(FacebookProfileNormalizer::class, $facebookProfileNormalizer); + $this->assertInstanceOf(LinkedinCompanyNormalizer::class, $linkedinCompanyProfileNormalizer); + $this->assertInstanceOf(NormalizerInterface::class, $twitterNormalizer); + $this->assertInstanceOf(NormalizerInterface::class, $facebookPageNormalizer); + $this->assertInstanceOf(NormalizerInterface::class, $facebookProfileNormalizer); + $this->assertInstanceOf(NormalizerInterface::class, $linkedinCompanyProfileNormalizer); + } + + public function testNormalizersFactoryException(): void + { + $this->expectException(NormalizeException::class); + + Factory::getForPlatform('foo'); + } + + public function testAddNormalizer(): void + { + $fakeNormalizer = new class implements NormalizerInterface { + public static function getPlatform(): string + { + return 'foo'; + } + + public function normalize(string $url): string + { + return $url; + } + + public function normalizeToId(string $url, array $settings = []): string + { + return $url; + } + + public function getPattern(): string + { + return '/foo/'; + } + }; + + Factory::addNormalizer($fakeNormalizer); + + $this->assertInstanceOf($fakeNormalizer::class, Factory::getForPlatform($fakeNormalizer::getPlatform())); + } +} diff --git a/tests/NormalizersTest.php b/tests/NormalizersTest.php index 722970e..389a01e 100644 --- a/tests/NormalizersTest.php +++ b/tests/NormalizersTest.php @@ -5,38 +5,29 @@ namespace Tests\Dealroom\SocialsHelpers; use Dealroom\SocialsHelpers\Exceptions\NormalizeException; +use Dealroom\SocialsHelpers\Normalizers\AppleMusicNormalizer; use Dealroom\SocialsHelpers\Normalizers\FacebookPageNormalizer; use Dealroom\SocialsHelpers\Normalizers\FacebookProfileNormalizer; use Dealroom\SocialsHelpers\Normalizers\Factory; +use Dealroom\SocialsHelpers\Normalizers\InstagramNormalizer; use Dealroom\SocialsHelpers\Normalizers\LinkedinCompanyNormalizer; -use Dealroom\SocialsHelpers\Normalizers\NormalizerInterface; +use Dealroom\SocialsHelpers\Normalizers\LinkedinProfileNormalizer; +use Dealroom\SocialsHelpers\Normalizers\LinkedinSchoolNormalizer; +use Dealroom\SocialsHelpers\Normalizers\LinkedinShowcaseNormalizer; +use Dealroom\SocialsHelpers\Normalizers\SoundcloudNormalizer; +use Dealroom\SocialsHelpers\Normalizers\SpotifyArtistNormalizer; +use Dealroom\SocialsHelpers\Normalizers\TikTokNormalizer; use Dealroom\SocialsHelpers\Normalizers\TwitterNormalizer; -use Dealroom\SocialsHelpers\Parser; +use Dealroom\SocialsHelpers\Normalizers\XNormalizer; +use Dealroom\SocialsHelpers\Normalizers\YoutubeNormalizer; use PHPUnit\Framework\TestCase; // phpcs:disable Generic.Files.LineLength.TooLong class NormalizersTest extends TestCase { - public function testNormalizersFactory(): void - { - $twitterNormalizer = Factory::getForPlatform(Parser::PLATFORM_TWITTER); - $facebookPageNormalizer = Factory::getForPlatform(Parser::PLATFORM_FACEBOOK_PAGE); - $facebookProfileNormalizer = Factory::getForPlatform(Parser::PLATFORM_FACEBOOK_PROFILE); - $linkedinCompanyProfileNormalizer = Factory::getForPlatform(Parser::PLATFORM_LINKEDIN_COMPANY); - - $this->assertInstanceOf(TwitterNormalizer::class, $twitterNormalizer); - $this->assertInstanceOf(FacebookPageNormalizer::class, $facebookPageNormalizer); - $this->assertInstanceOf(FacebookProfileNormalizer::class, $facebookProfileNormalizer); - $this->assertInstanceOf(LinkedinCompanyNormalizer::class, $linkedinCompanyProfileNormalizer); - $this->assertInstanceOf(NormalizerInterface::class, $twitterNormalizer); - $this->assertInstanceOf(NormalizerInterface::class, $facebookPageNormalizer); - $this->assertInstanceOf(NormalizerInterface::class, $facebookProfileNormalizer); - $this->assertInstanceOf(NormalizerInterface::class, $linkedinCompanyProfileNormalizer); - } - public function testTwitterNormalizer(): void { - $twitterNormalizer = Factory::getForPlatform(Parser::PLATFORM_TWITTER); + $twitterNormalizer = Factory::getForPlatform(TwitterNormalizer::getPlatform()); $values = [ 'http://www.twitter.com/codeschool/dasd?dsadasd' => 'https://twitter.com/codeschool', @@ -62,7 +53,7 @@ public function testTwitterNormalizer(): void public function testXNormalizer(): void { - $twitterNormalizer = Factory::getForPlatform(Parser::PLATFORM_X); + $twitterNormalizer = Factory::getForPlatform(XNormalizer::getPlatform()); $values = [ 'http://www.x.com/codeschool/dasd?dsadasd' => 'https://x.com/codeschool', @@ -88,7 +79,7 @@ public function testXNormalizer(): void public function testFacebookPageNormalizer(): void { - $facebookPageNormalizer = Factory::getForPlatform(Parser::PLATFORM_FACEBOOK_PAGE); + $facebookPageNormalizer = Factory::getForPlatform(FacebookPageNormalizer::getPlatform()); $values = [ @@ -97,22 +88,22 @@ public function testFacebookPageNormalizer(): void 'http://facebook.com/dizzain?pnref=lhc' => 'https://www.facebook.com/dizzain', 'https://facebook.com/dizzain?pnref=lhc' => 'https://www.facebook.com/dizzain', 'https://facebook.com/Dizzain?pnref=lhc' => 'https://www.facebook.com/dizzain', - 'https://www.facebook.com/pages/fasdfadsfasdfsadf/126287147568059?pnref=lhc' => 'https://www.facebook.com/pages/fasdfadsfasdfsadf/126287147568059', + 'https://www.facebook.com/pages/fasdfadsfasdfsadf/126287147568059?pnref=lhc' => 'https://www.facebook.com/126287147568059', 'https://www.facebook.com/PHPtoday-1025912177431644/?fref=ts' => 'https://www.facebook.com/phptoday-1025912177431644', - 'http://www.facebook.com/pages/The-bloomtrigger-project/125218650866978/fasdfas?asdas' => 'https://www.facebook.com/pages/the-bloomtrigger-project/125218650866978', - 'http://www.facebook.com/pages/DealMarket/157833714232772' => 'https://www.facebook.com/pages/dealmarket/157833714232772', - 'http://www.facebook.com/#!/pages/dealmarket/157833714232772' => 'https://www.facebook.com/pages/dealmarket/157833714232772', - 'http://www.facebook.com/pages/san-diego-ca/layer3-security-services/207635209271099' => 'https://www.facebook.com/pages/san-diego-ca/layer3-security-services/207635209271099', - 'http://www.facebook.com/pages/agility+inc./114838698562760' => 'https://www.facebook.com/pages/agility+inc./114838698562760', - 'http://www.facebook.com/pages/karen-mali-m%c3%bc%c5%9favirlik-logo-muhasebe/194296120603783' => 'https://www.facebook.com/pages/karen-mali-m%c3%bc%c5%9favirlik-logo-muhasebe/194296120603783', - 'http://www.facebook.com//pages/custom-case-guy/1445342082363874' => 'https://www.facebook.com/pages/custom-case-guy/1445342082363874', + 'http://www.facebook.com/pages/The-bloomtrigger-project/125218650866978/fasdfas?asdas' => 'https://www.facebook.com/125218650866978', + 'http://www.facebook.com/pages/DealMarket/157833714232772' => 'https://www.facebook.com/157833714232772', + 'http://www.facebook.com/#!/pages/dealmarket/157833714232772' => 'https://www.facebook.com/157833714232772', + 'http://www.facebook.com/pages/san-diego-ca/layer3-security-services/207635209271099' => 'https://www.facebook.com/207635209271099', + 'http://www.facebook.com/pages/agility+inc./114838698562760' => 'https://www.facebook.com/114838698562760', + 'http://www.facebook.com/pages/karen-mali-m%c3%bc%c5%9favirlik-logo-muhasebe/194296120603783' => 'https://www.facebook.com/194296120603783', + 'http://www.facebook.com//pages/custom-case-guy/1445342082363874' => 'https://www.facebook.com/1445342082363874', 'https://en-gb.facebook.com/wonderbill/' => 'https://www.facebook.com/wonderbill', 'https://business.facebook.com/TectradeHQ/?business_id=284925295380988&ref=bookmarks' => 'https://www.facebook.com/tectradehq', 'https://web.facebook.com/dermexpert/' => 'https://www.facebook.com/dermexpert', 'https://m.facebook.com/umadic1/' => 'https://www.facebook.com/umadic1', 'https://p-upload.facebook.com/epicvue/' => 'https://www.facebook.com/epicvue', - 'https://www.facebook.com/pages/Torrent-Pharmaceuticals-Limited/398754970290333' => 'https://www.facebook.com/pages/torrent-pharmaceuticals-limited/398754970290333', - 'https://en-gb.facebook.com/pages/Torrent-Pharmaceuticals-Limited/398754970290333' => 'https://www.facebook.com/pages/torrent-pharmaceuticals-limited/398754970290333', + 'https://www.facebook.com/pages/Torrent-Pharmaceuticals-Limited/398754970290333' => 'https://www.facebook.com/398754970290333', + 'https://en-gb.facebook.com/pages/Torrent-Pharmaceuticals-Limited/398754970290333' => 'https://www.facebook.com/398754970290333', ]; foreach ($values as $source => $result) { @@ -122,7 +113,7 @@ public function testFacebookPageNormalizer(): void public function testFacebookPageNormalizerErrors(): void { - $facebookPageNormalizer = Factory::getForPlatform(Parser::PLATFORM_FACEBOOK_PAGE); + $facebookPageNormalizer = Factory::getForPlatform(FacebookPageNormalizer::getPlatform()); $values = [ 'http://www.facebook.com/home.php?tests#!/pages/dealmarket/157833714232772', @@ -136,10 +127,10 @@ public function testFacebookPageNormalizerErrors(): void public function testFacebookProfileNormalizer(): void { - $facebookProfileNormalizer = Factory::getForPlatform(Parser::PLATFORM_FACEBOOK_PROFILE); + $facebookProfileNormalizer = Factory::getForPlatform(FacebookProfileNormalizer::getPlatform()); $values = [ - 'http://www.facebook.com/people/_/100000049946330' => 'https://www.facebook.com/people/_/100000049946330', + 'http://www.facebook.com/people/_/100000049946330' => 'https://www.facebook.com/profile.php?id=100000049946330', 'http://www.facebook.com/profile.php?id=1294422029' => 'https://www.facebook.com/profile.php?id=1294422029', 'http://www.facebook.com/profile.php?id=1294422029/' => 'https://www.facebook.com/profile.php?id=1294422029', 'http://facebook.com/profile.php?id=1294422029' => 'https://www.facebook.com/profile.php?id=1294422029', @@ -151,9 +142,26 @@ public function testFacebookProfileNormalizer(): void } } + //InstagramNormalizer + public function testInstagramNormalizer(): void + { + $instagramNormalizer = Factory::getForPlatform(InstagramNormalizer::getPlatform()); + + $values = [ + 'https://www.instagram.com/kevin' => 'https://www.instagram.com/kevin', + 'https://www.instagram.com/kevin/' => 'https://www.instagram.com/kevin', + 'https://instagram.com/kevin' => 'https://www.instagram.com/kevin', + 'http://www.instagram.com/kevin' => 'https://www.instagram.com/kevin', + ]; + + foreach ($values as $source => $result) { + $this->assertEquals($result, $instagramNormalizer->normalize($source)); + } + } + public function testLinkedinCompanyNormalizer(): void { - $linkedinCompanyProfileNormalizer = Factory::getForPlatform(Parser::PLATFORM_LINKEDIN_COMPANY); + $linkedinCompanyProfileNormalizer = Factory::getForPlatform(LinkedinCompanyNormalizer::getPlatform()); $values = [ 'https://www.linkedin.com/company/dealroom/' => 'https://www.linkedin.com/company/dealroom/', @@ -178,7 +186,7 @@ public function testLinkedinCompanyNormalizer(): void public function testLinkedinShowcaseNormalizer(): void { - $linkedinShowcaseNormalizer = Factory::getForPlatform(Parser::PLATFORM_LINKEDIN_SHOWCASE); + $linkedinShowcaseNormalizer = Factory::getForPlatform(LinkedinShowcaseNormalizer::getPlatform()); $values = [ 'https://www.linkedin.com/showcase/dealroom/' => 'https://www.linkedin.com/showcase/dealroom/', @@ -203,7 +211,7 @@ public function testLinkedinShowcaseNormalizer(): void public function testLinkedinSchoolNormalizer(): void { - $linkedinSchoolNormalizer = Factory::getForPlatform(Parser::PLATFORM_LINKEDIN_SCHOOL); + $linkedinSchoolNormalizer = Factory::getForPlatform(LinkedinSchoolNormalizer::getPlatform()); $values = [ 'https://www.linkedin.com/school/dealroom/' => 'https://www.linkedin.com/school/dealroom/', @@ -228,7 +236,7 @@ public function testLinkedinSchoolNormalizer(): void public function testLinkedinProfileNormalizer(): void { - $linkedinSchoolNormalizer = Factory::getForPlatform(Parser::PLATFORM_LINKEDIN_PROFILE); + $linkedinProfileNormalizer = Factory::getForPlatform(LinkedinProfileNormalizer::getPlatform()); $values = [ 'https://www.linkedin.com/in/dealroom/' => 'https://www.linkedin.com/in/dealroom/', @@ -239,20 +247,108 @@ public function testLinkedinProfileNormalizer(): void ]; foreach ($values as $source => $result) { - $this->assertEquals($result, $linkedinSchoolNormalizer->normalize($source)); + $this->assertEquals($result, $linkedinProfileNormalizer->normalize($source)); + } + } + + public function testTikTokNormalizer(): void + { + $tikTokNormalizer = Factory::getForPlatform(TikTokNormalizer::getPlatform()); + + $values = [ + 'https://www.tiktok.com/@khaby.lame' => 'https://www.tiktok.com/@khaby.lame', + 'https://www.tiktok.com/@charlidamelio' => 'https://www.tiktok.com/@charlidamelio', + 'https://www.tiktok.com/@bts_official_bighit' => 'https://www.tiktok.com/@bts_official_bighit', + 'https://tiktok.com/@tiktok' => 'https://www.tiktok.com/@tiktok', + 'http://www.tiktok.com/@tiktok' => 'https://www.tiktok.com/@tiktok', + ]; + + foreach ($values as $source => $result) { + $this->assertEquals($result, $tikTokNormalizer->normalize($source)); + } + } + + public function testAppleMusicNormalizer(): void + { + $appleMusicNormalizer = Factory::getForPlatform(AppleMusicNormalizer::getPlatform()); + + $values = [ + 'https://music.apple.com/us/artist/the-beatles/136975' => 'https://music.apple.com/artist/136975', + 'https://music.apple.com/us/artist/beatles/136975' => 'https://music.apple.com/artist/136975', + 'https://music.apple.com/artist/beatles/136975' => 'https://music.apple.com/artist/136975', + 'https://music.apple.com/artist/136975' => 'https://music.apple.com/artist/136975', + 'https://itunes.apple.com/us/artist/id136975' => 'https://music.apple.com/artist/136975', + ]; + + foreach ($values as $source => $result) { + $this->assertEquals($result, $appleMusicNormalizer->normalize($source)); + } + } + + public function testSoundcloudNormalizer(): void + { + $soundcloudNormalizer = Factory::getForPlatform(SoundcloudNormalizer::getPlatform()); + + $values = [ + 'https://soundcloud.com/kx5-music' => 'https://soundcloud.com/kx5-music', + 'https://soundcloud.com/kx5official' => 'https://soundcloud.com/kx5official', + ]; + + foreach ($values as $source => $result) { + $this->assertEquals($result, $soundcloudNormalizer->normalize($source)); + } + } + + public function testSpotifyArtistNormalizer(): void + { + $spotifyArtistNormalizer = Factory::getForPlatform(SpotifyArtistNormalizer::getPlatform()); + + $values = [ + 'https://open.spotify.com/artist/3WrFJ7ztbogyGnTHbHJFl2' => 'https://open.spotify.com/artist/3WrFJ7ztbogyGnTHbHJFl2', + 'spotify:artist:3WrFJ7ztbogyGnTHbHJFl2' => 'https://open.spotify.com/artist/3WrFJ7ztbogyGnTHbHJFl2', + ]; + + foreach ($values as $source => $result) { + $this->assertEquals($result, $spotifyArtistNormalizer->normalize($source)); + } + } + + public function testYoutubeNormalizer(): void + { + $youtubeNormalizer = Factory::getForPlatform(YoutubeNormalizer::getPlatform()); + + $values = [ + 'https://www.youtube.com/channel/UCJow9j3zvZ4vK2ZjUwZc6Fw' => 'https://www.youtube.com/channel/UCJow9j3zvZ4vK2ZjUwZc6Fw', + 'https://www.youtube.com/user/Google' => 'https://www.youtube.com/Google', + 'https://www.youtube.com/c/Google' => 'https://www.youtube.com/Google', + 'https://www.youtube.com/Google' => 'https://www.youtube.com/Google', + 'https://www.youtube.com/Google/' => 'https://www.youtube.com/Google', + 'https://www.youtube.com/Google/about' => 'https://www.youtube.com/Google', + 'https://www.youtube.com/Google/videos' => 'https://www.youtube.com/Google', + 'https://www.youtube.com/Google/playlists' => 'https://www.youtube.com/Google', + 'https://www.youtube.com/Google/community' => 'https://www.youtube.com/Google', + 'https://www.youtube.com/Google/channels' => 'https://www.youtube.com/Google', + 'https://www.youtube.com/Google/featured' => 'https://www.youtube.com/Google', + 'https://www.youtube.com/Google/live' => 'https://www.youtube.com/Google', + 'https://youtube.com/Google' => 'https://www.youtube.com/Google', + 'http://www.youtube.com/Google' => 'https://www.youtube.com/Google', + ]; + + foreach ($values as $source => $result) { + $this->assertEquals($result, $youtubeNormalizer->normalize($source)); } } public function testNormalizerToId(): void { $values = [ - 'https://twitter.com/codeschool' => [Parser::PLATFORM_TWITTER, 'codeschool'], - 'https://www.facebook.com/dizzain' => [Parser::PLATFORM_FACEBOOK_PAGE, ''], - 'https://www.facebook.com/profile.php?id=1294422029' => [Parser::PLATFORM_FACEBOOK_PROFILE, '1294422029'], - 'https://www.linkedin.com/company/dealroom/' => [Parser::PLATFORM_LINKEDIN_COMPANY, 'dealroom'], - 'https://www.linkedin.com/showcase/dealroom/' => [Parser::PLATFORM_LINKEDIN_SHOWCASE, 'dealroom'], - 'https://www.linkedin.com/school/dealroom//' => [Parser::PLATFORM_LINKEDIN_SCHOOL, 'dealroom'], - 'https://www.linkedin.com/in/dealroom//' => [Parser::PLATFORM_LINKEDIN_PROFILE, 'dealroom'], + 'https://twitter.com/codeschool' => [TwitterNormalizer::getPlatform(), 'codeschool'], + 'https://www.facebook.com/dizzain' => [FacebookPageNormalizer::getPlatform(), 'dizzain'], + 'https://www.facebook.com/profile.php?id=1294422029' => [FacebookProfileNormalizer::getPlatform(), '1294422029'], + 'https://www.linkedin.com/company/dealroom/' => [LinkedinCompanyNormalizer::getPlatform(), 'dealroom'], + 'https://www.linkedin.com/showcase/dealroom/' => [LinkedinShowcaseNormalizer::getPlatform(), 'dealroom'], + 'https://www.linkedin.com/school/dealroom//' => [LinkedinSchoolNormalizer::getPlatform(), 'dealroom'], + 'https://www.linkedin.com/in/dealroom//' => [LinkedinProfileNormalizer::getPlatform(), 'dealroom'], ]; foreach ($values as $url => $row) { diff --git a/tests/ResultTest.php b/tests/ResultTest.php index 7c8f893..742c22a 100644 --- a/tests/ResultTest.php +++ b/tests/ResultTest.php @@ -5,7 +5,7 @@ namespace Tests\Dealroom\SocialsHelpers; use Dealroom\SocialsHelpers\Factory; -use Dealroom\SocialsHelpers\Parser; +use Dealroom\SocialsHelpers\Normalizers\TwitterNormalizer; use PHPUnit\Framework\TestCase; class ResultTest extends TestCase @@ -16,8 +16,9 @@ public function testResultMethods(): void $result = Factory::parseUrl($url); - $this->assertEquals(Parser::PLATFORM_TWITTER, $result->getPlatform()); - $this->assertEquals(strtolower($url), $result->getUrl()); + $this->assertEquals(TwitterNormalizer::getPlatform(), $result->getPlatform()); + $this->assertEquals($url, $result->getUrl()); $this->assertEquals('https://twitter.com/dealroom', $result->getNormalizedUrl()); + $this->assertEquals('dealroom', $result->getId()); } }