Skip to content

Commit

Permalink
Merge pull request #158 from dealroom/ultramusicfestival/main
Browse files Browse the repository at this point in the history
Socials Helpers v3 #major
  • Loading branch information
pfuhrmann authored Jul 2, 2024
2 parents 8293f96 + 3396236 commit 885d2a7
Show file tree
Hide file tree
Showing 27 changed files with 550 additions and 391 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
.idea
.phpunit.cache/
.phpunit.result.cache
.composer.lock
composer.lock
54 changes: 50 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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;
Expand All @@ -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
Expand All @@ -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/).
6 changes: 3 additions & 3 deletions composer.json
Original file line number Diff line number Diff line change
@@ -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"
Expand Down
9 changes: 2 additions & 7 deletions src/Factory.php
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
50 changes: 47 additions & 3 deletions src/Normalizers/AbstractNormalizer.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}
21 changes: 21 additions & 0 deletions src/Normalizers/AppleMusicNormalizer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php

declare(strict_types=1);

namespace Dealroom\SocialsHelpers\Normalizers;

class AppleMusicNormalizer extends AbstractNormalizer
{
public static function getPlatform(): string
{
return 'apple_music';
}

// phpcs:disable Generic.Files.LineLength.TooLong
protected string $pattern = '/https?:\/\/(?:itunes|music)\.apple\.com\/(?:[\pL]{2}\/)?artist\/(?:[\pL\d_\-\%\.]+\/)?(?:id)?([\d]+)/';
// phpcs:enable Generic.Files.LineLength.TooLong

protected string $normalizedUrl = 'https://music.apple.com/artist/%s';

protected array|int $idPosition = 1;
}
62 changes: 7 additions & 55 deletions src/Normalizers/FacebookPageNormalizer.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,66 +4,18 @@

namespace Dealroom\SocialsHelpers\Normalizers;

use Dealroom\SocialsHelpers\Exceptions\NormalizeException;

class FacebookPageNormalizer extends AbstractNormalizer
{
public function normalize(string $url): string
public static function getPlatform(): string
{
$url = parent::normalize($url);

if (str_contains($url, 'fb.com')) {
$url = str_replace('fb.com', 'facebook.com', $url);
}

if (str_contains($url, '/pages/')) {
// 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\-+.%,()]+\/\d+/', $url, $matches);
if ($result) {
$matches = $this->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];
}
22 changes: 5 additions & 17 deletions src/Normalizers/FacebookProfileNormalizer.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
48 changes: 30 additions & 18 deletions src/Normalizers/Factory.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}
19 changes: 19 additions & 0 deletions src/Normalizers/InstagramNormalizer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php

declare(strict_types=1);

namespace Dealroom\SocialsHelpers\Normalizers;

class InstagramNormalizer extends AbstractNormalizer
{
public static function getPlatform(): string
{
return 'instagram';
}

protected string $pattern = '/https?:\/\/(?:www\.)?instagram\.com\/(?!about|legal|explore|web)([\pL\d\_\.]{1,30})/';

protected string $normalizedUrl = 'https://www.instagram.com/%s';

protected array|int $idPosition = 1;
}
Loading

0 comments on commit 885d2a7

Please sign in to comment.