Remove usage of Functional\map function

This commit is contained in:
Alejandro Celaya
2023-11-29 12:34:13 +01:00
parent a91a560651
commit f50263d2d9
37 changed files with 201 additions and 140 deletions

View File

@@ -199,7 +199,7 @@ services:
shlink_swagger_ui: shlink_swagger_ui:
container_name: shlink_swagger_ui container_name: shlink_swagger_ui
image: swaggerapi/swagger-ui:v5.9.1 image: swaggerapi/swagger-ui:v5.10.3
ports: ports:
- "8005:8080" - "8005:8080"
volumes: volumes:

View File

@@ -15,7 +15,7 @@ use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Output\OutputInterface;
use function array_filter; use function array_filter;
use function Functional\map; use function array_map;
use function implode; use function implode;
use function sprintf; use function sprintf;
@@ -49,7 +49,7 @@ class ListKeysCommand extends Command
{ {
$enabledOnly = $input->getOption('enabled-only'); $enabledOnly = $input->getOption('enabled-only');
$rows = map($this->apiKeyService->listKeys($enabledOnly), function (ApiKey $apiKey) use ($enabledOnly) { $rows = array_map(function (ApiKey $apiKey) use ($enabledOnly) {
$expiration = $apiKey->getExpirationDate(); $expiration = $apiKey->getExpirationDate();
$messagePattern = $this->determineMessagePattern($apiKey); $messagePattern = $this->determineMessagePattern($apiKey);
@@ -64,7 +64,7 @@ class ListKeysCommand extends Command
)); ));
return $rowData; return $rowData;
}); }, $this->apiKeyService->listKeys($enabledOnly));
ShlinkTable::withRowSeparators($output)->render(array_filter([ ShlinkTable::withRowSeparators($output)->render(array_filter([
'Key', 'Key',

View File

@@ -16,8 +16,8 @@ use Symfony\Component\Lock\LockFactory;
use Symfony\Component\Process\PhpExecutableFinder; use Symfony\Component\Process\PhpExecutableFinder;
use Throwable; use Throwable;
use function array_map;
use function Functional\contains; use function Functional\contains;
use function Functional\map;
use function Functional\some; use function Functional\some;
class CreateDatabaseCommand extends AbstractDatabaseCommand class CreateDatabaseCommand extends AbstractDatabaseCommand
@@ -70,7 +70,7 @@ class CreateDatabaseCommand extends AbstractDatabaseCommand
{ {
$existingTables = $this->ensureDatabaseExistsAndGetTables(); $existingTables = $this->ensureDatabaseExistsAndGetTables();
$allMetadata = $this->em->getMetadataFactory()->getAllMetadata(); $allMetadata = $this->em->getMetadataFactory()->getAllMetadata();
$shlinkTables = map($allMetadata, static fn (ClassMetadata $metadata) => $metadata->getTableName()); $shlinkTables = array_map(static fn (ClassMetadata $metadata) => $metadata->getTableName(), $allMetadata);
// If at least one of the shlink tables exist, we will consider the database exists somehow. // If at least one of the shlink tables exist, we will consider the database exists somehow.
// Any other inconsistency will be taken care of by the migrations. // Any other inconsistency will be taken care of by the migrations.

View File

@@ -14,13 +14,13 @@ use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Output\OutputInterface;
use function Functional\map; use function array_map;
class ListDomainsCommand extends Command class ListDomainsCommand extends Command
{ {
public const NAME = 'domain:list'; public const NAME = 'domain:list';
public function __construct(private DomainServiceInterface $domainService) public function __construct(private readonly DomainServiceInterface $domainService)
{ {
parent::__construct(); parent::__construct();
} }
@@ -47,7 +47,7 @@ class ListDomainsCommand extends Command
$table->render( $table->render(
$showRedirects ? [...$commonFields, '"Not found" redirects'] : $commonFields, $showRedirects ? [...$commonFields, '"Not found" redirects'] : $commonFields,
map($domains, function (DomainItem $domain) use ($showRedirects) { array_map(function (DomainItem $domain) use ($showRedirects) {
$commonValues = [$domain->toString(), $domain->isDefault ? 'Yes' : 'No']; $commonValues = [$domain->toString(), $domain->isDefault ? 'Yes' : 'No'];
return $showRedirects return $showRedirects
@@ -56,7 +56,7 @@ class ListDomainsCommand extends Command
$this->notFoundRedirectsToString($domain->notFoundRedirectConfig), $this->notFoundRedirectsToString($domain->notFoundRedirectConfig),
] ]
: $commonValues; : $commonValues;
}), }, $domains),
); );
return ExitCode::EXIT_SUCCESS; return ExitCode::EXIT_SUCCESS;

View File

@@ -23,9 +23,9 @@ use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle; use Symfony\Component\Console\Style\SymfonyStyle;
use function array_keys; use function array_keys;
use function array_map;
use function array_pad; use function array_pad;
use function explode; use function explode;
use function Functional\map;
use function implode; use function implode;
use function sprintf; use function sprintf;
@@ -184,10 +184,10 @@ class ListShortUrlsCommand extends Command
): Paginator { ): Paginator {
$shortUrls = $this->shortUrlService->listShortUrls($params); $shortUrls = $this->shortUrlService->listShortUrls($params);
$rows = map($shortUrls, function (ShortUrl $shortUrl) use ($columnsMap) { $rows = array_map(function (ShortUrl $shortUrl) use ($columnsMap) {
$rawShortUrl = $this->transformer->transform($shortUrl); $rawShortUrl = $this->transformer->transform($shortUrl);
return map($columnsMap, fn (callable $call) => $call($rawShortUrl, $shortUrl)); return array_map(fn (callable $call) => $call($rawShortUrl, $shortUrl), $columnsMap);
}); }, [...$shortUrls]);
ShlinkTable::default($output)->render( ShlinkTable::default($output)->render(
array_keys($columnsMap), array_keys($columnsMap),

View File

@@ -13,13 +13,13 @@ use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Output\OutputInterface;
use function Functional\map; use function array_map;
class ListTagsCommand extends Command class ListTagsCommand extends Command
{ {
public const NAME = 'tag:list'; public const NAME = 'tag:list';
public function __construct(private TagServiceInterface $tagService) public function __construct(private readonly TagServiceInterface $tagService)
{ {
parent::__construct(); parent::__construct();
} }
@@ -44,9 +44,9 @@ class ListTagsCommand extends Command
return [['No tags found', '-', '-']]; return [['No tags found', '-', '-']];
} }
return map( return array_map(
$tags,
static fn (TagInfo $tagInfo) => [$tagInfo->tag, $tagInfo->shortUrlsCount, $tagInfo->visitsSummary->total], static fn (TagInfo $tagInfo) => [$tagInfo->tag, $tagInfo->shortUrlsCount, $tagInfo->visitsSummary->total],
[...$tags],
); );
} }
} }

View File

@@ -16,12 +16,15 @@ use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Output\OutputInterface;
use function array_filter;
use function array_keys; use function array_keys;
use function Functional\map; use function array_map;
use function Functional\select_keys; use function in_array;
use function Shlinkio\Shlink\Common\buildDateRange; use function Shlinkio\Shlink\Common\buildDateRange;
use function Shlinkio\Shlink\Core\camelCaseToHumanFriendly; use function Shlinkio\Shlink\Core\camelCaseToHumanFriendly;
use const ARRAY_FILTER_USE_KEY;
abstract class AbstractVisitsListCommand extends Command abstract class AbstractVisitsListCommand extends Command
{ {
private readonly StartDateOption $startDateOption; private readonly StartDateOption $startDateOption;
@@ -49,7 +52,7 @@ abstract class AbstractVisitsListCommand extends Command
private function resolveRowsAndHeaders(Paginator $paginator): array private function resolveRowsAndHeaders(Paginator $paginator): array
{ {
$extraKeys = []; $extraKeys = [];
$rows = map($paginator->getCurrentPageResults(), function (Visit $visit) use (&$extraKeys) { $rows = array_map(function (Visit $visit) use (&$extraKeys) {
$extraFields = $this->mapExtraFields($visit); $extraFields = $this->mapExtraFields($visit);
$extraKeys = array_keys($extraFields); $extraKeys = array_keys($extraFields);
@@ -60,9 +63,18 @@ abstract class AbstractVisitsListCommand extends Command
...$extraFields, ...$extraFields,
]; ];
return select_keys($rowData, ['referer', 'date', 'userAgent', 'country', 'city', ...$extraKeys]); // Filter out unknown keys
}); return array_filter(
$extra = map($extraKeys, camelCaseToHumanFriendly(...)); $rowData,
static fn (string $key) => in_array(
$key,
['referer', 'date', 'userAgent', 'country', 'city', ...$extraKeys],
strict: true,
),
ARRAY_FILTER_USE_KEY,
);
}, [...$paginator->getCurrentPageResults()]);
$extra = array_map(camelCaseToHumanFriendly(...), $extraKeys);
return [ return [
$rows, $rows,

View File

@@ -16,8 +16,6 @@ use Shlinkio\Shlink\Rest\ApiKey\Model\RoleDefinition;
use Shlinkio\Shlink\Rest\ApiKey\Role; use Shlinkio\Shlink\Rest\ApiKey\Role;
use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputInterface;
use function Functional\map;
class RoleResolverTest extends TestCase class RoleResolverTest extends TestCase
{ {
private RoleResolver $resolver; private RoleResolver $resolver;
@@ -49,10 +47,13 @@ class RoleResolverTest extends TestCase
{ {
$domain = self::domainWithId(Domain::withAuthority('example.com')); $domain = self::domainWithId(Domain::withAuthority('example.com'));
$buildInput = static fn (array $definition) => function (TestCase $test) use ($definition): InputInterface { $buildInput = static fn (array $definition) => function (TestCase $test) use ($definition): InputInterface {
$returnMap = [];
foreach ($definition as $param => $returnValue) {
$returnMap[] = [$param, $returnValue];
}
$input = $test->createStub(InputInterface::class); $input = $test->createStub(InputInterface::class);
$input->method('getOption')->willReturnMap( $input->method('getOption')->willReturnMap($returnMap);
map($definition, static fn (mixed $returnValue, string $param) => [$param, $returnValue]),
);
return $input; return $input;
}; };

View File

@@ -21,7 +21,7 @@ use Shlinkio\Shlink\IpGeolocation\GeoLite2\DbUpdaterInterface;
use Symfony\Component\Lock; use Symfony\Component\Lock;
use Throwable; use Throwable;
use function Functional\map; use function array_map;
use function range; use function range;
class GeolocationDbUpdaterTest extends TestCase class GeolocationDbUpdaterTest extends TestCase
@@ -128,7 +128,7 @@ class GeolocationDbUpdaterTest extends TestCase
return [$days % 2 === 0 ? $timestamp : (string) $timestamp]; return [$days % 2 === 0 ? $timestamp : (string) $timestamp];
}; };
return map(range(0, 34), $generateParamsWithTimestamp); return array_map($generateParamsWithTimestamp, range(0, 34));
} }
#[Test] #[Test]

View File

@@ -17,8 +17,8 @@ use PUGX\Shortid\Factory as ShortIdFactory;
use Shlinkio\Shlink\Common\Util\DateRange; use Shlinkio\Shlink\Common\Util\DateRange;
use Shlinkio\Shlink\Core\ShortUrl\Model\ShortUrlMode; use Shlinkio\Shlink\Core\ShortUrl\Model\ShortUrlMode;
use function array_map;
use function date_default_timezone_get; use function date_default_timezone_get;
use function Functional\map;
use function Functional\reduce_left; use function Functional\reduce_left;
use function is_array; use function is_array;
use function print_r; use function print_r;
@@ -177,6 +177,6 @@ function enumValues(string $enum): array
} }
return $cache[$enum] ?? ( return $cache[$enum] ?? (
$cache[$enum] = map($enum::cases(), static fn (BackedEnum $type) => (string) $type->value) $cache[$enum] = array_map(static fn (BackedEnum $type) => (string) $type->value, $enum::cases())
); );
} }

View File

@@ -4,7 +4,7 @@ declare(strict_types=1);
namespace Shlinkio\Shlink\Core\Config\PostProcessor; namespace Shlinkio\Shlink\Core\Config\PostProcessor;
use function Functional\map; use function array_map;
class BasePathPrefixer class BasePathPrefixer
{ {
@@ -23,13 +23,13 @@ class BasePathPrefixer
private function prefixPathsWithBasePath(string $configKey, array $config, string $basePath): array private function prefixPathsWithBasePath(string $configKey, array $config, string $basePath): array
{ {
return map($config[$configKey] ?? [], function (array $element) use ($basePath) { return array_map(function (array $element) use ($basePath) {
if (! isset($element['path'])) { if (! isset($element['path'])) {
return $element; return $element;
} }
$element['path'] = $basePath . $element['path']; $element['path'] = $basePath . $element['path'];
return $element; return $element;
}); }, $config[$configKey] ?? []);
} }
} }

View File

@@ -4,7 +4,7 @@ declare(strict_types=1);
namespace Shlinkio\Shlink\Core\Config\PostProcessor; namespace Shlinkio\Shlink\Core\Config\PostProcessor;
use function Functional\map; use function array_map;
use function str_replace; use function str_replace;
class MultiSegmentSlugProcessor class MultiSegmentSlugProcessor
@@ -19,11 +19,11 @@ class MultiSegmentSlugProcessor
return $config; return $config;
} }
$config['routes'] = map($config['routes'] ?? [], static function (array $route): array { $config['routes'] = array_map(static function (array $route): array {
['path' => $path] = $route; ['path' => $path] = $route;
$route['path'] = str_replace(self::SINGLE_SEGMENT_PATTERN, self::MULTI_SEGMENT_PATTERN, $path); $route['path'] = str_replace(self::SINGLE_SEGMENT_PATTERN, self::MULTI_SEGMENT_PATTERN, $path);
return $route; return $route;
}); }, $config['routes'] ?? []);
return $config; return $config;
} }

View File

@@ -14,9 +14,9 @@ use Shlinkio\Shlink\Core\Exception\DomainNotFoundException;
use Shlinkio\Shlink\Rest\ApiKey\Role; use Shlinkio\Shlink\Rest\ApiKey\Role;
use Shlinkio\Shlink\Rest\Entity\ApiKey; use Shlinkio\Shlink\Rest\Entity\ApiKey;
use function array_map;
use function Functional\first; use function Functional\first;
use function Functional\group; use function Functional\group;
use function Functional\map;
class DomainService implements DomainServiceInterface class DomainService implements DomainServiceInterface
{ {
@@ -30,7 +30,7 @@ class DomainService implements DomainServiceInterface
public function listDomains(?ApiKey $apiKey = null): array public function listDomains(?ApiKey $apiKey = null): array
{ {
[$default, $domains] = $this->defaultDomainAndRest($apiKey); [$default, $domains] = $this->defaultDomainAndRest($apiKey);
$mappedDomains = map($domains, fn (Domain $domain) => DomainItem::forNonDefaultDomain($domain)); $mappedDomains = array_map(fn (Domain $domain) => DomainItem::forNonDefaultDomain($domain), $domains);
if ($apiKey?->hasRole(Role::DOMAIN_SPECIFIC)) { if ($apiKey?->hasRole(Role::DOMAIN_SPECIFIC)) {
return $mappedDomains; return $mappedDomains;

View File

@@ -19,18 +19,18 @@ use Shlinkio\Shlink\Core\Options\WebhookOptions;
use Shlinkio\Shlink\Core\Visit\Entity\Visit; use Shlinkio\Shlink\Core\Visit\Entity\Visit;
use Throwable; use Throwable;
use function Functional\map; use function array_map;
/** @deprecated */ /** @deprecated */
class NotifyVisitToWebHooks class NotifyVisitToWebHooks
{ {
public function __construct( public function __construct(
private ClientInterface $httpClient, private readonly ClientInterface $httpClient,
private EntityManagerInterface $em, private readonly EntityManagerInterface $em,
private LoggerInterface $logger, private readonly LoggerInterface $logger,
private WebhookOptions $webhookOptions, private readonly WebhookOptions $webhookOptions,
private DataTransformerInterface $transformer, private readonly DataTransformerInterface $transformer,
private AppOptions $appOptions, private readonly AppOptions $appOptions,
) { ) {
} }
@@ -82,11 +82,11 @@ class NotifyVisitToWebHooks
*/ */
private function performRequests(array $requestOptions, string $visitId): array private function performRequests(array $requestOptions, string $visitId): array
{ {
return map( return array_map(
$this->webhookOptions->webhooks(),
fn (string $webhook): PromiseInterface => $this->httpClient fn (string $webhook): PromiseInterface => $this->httpClient
->requestAsync(RequestMethodInterface::METHOD_POST, $webhook, $requestOptions) ->requestAsync(RequestMethodInterface::METHOD_POST, $webhook, $requestOptions)
->otherwise(fn (Throwable $e) => $this->logWebhookFailure($webhook, $visitId, $e)), ->otherwise(fn (Throwable $e) => $this->logWebhookFailure($webhook, $visitId, $e)),
$this->webhookOptions->webhooks(),
); );
} }

View File

@@ -27,8 +27,8 @@ use Shlinkio\Shlink\Importer\Model\ImportedShlinkUrl;
use Shlinkio\Shlink\Rest\Entity\ApiKey; use Shlinkio\Shlink\Rest\Entity\ApiKey;
use function array_fill_keys; use function array_fill_keys;
use function array_map;
use function count; use function count;
use function Functional\map;
use function Shlinkio\Shlink\Core\enumValues; use function Shlinkio\Shlink\Core\enumValues;
use function Shlinkio\Shlink\Core\generateRandomShortCode; use function Shlinkio\Shlink\Core\generateRandomShortCode;
use function Shlinkio\Shlink\Core\normalizeDate; use function Shlinkio\Shlink\Core\normalizeDate;
@@ -90,9 +90,9 @@ class ShortUrl extends AbstractEntity
$instance->longUrl = $creation->getLongUrl(); $instance->longUrl = $creation->getLongUrl();
$instance->dateCreated = Chronos::now(); $instance->dateCreated = Chronos::now();
$instance->visits = new ArrayCollection(); $instance->visits = new ArrayCollection();
$instance->deviceLongUrls = new ArrayCollection(map( $instance->deviceLongUrls = new ArrayCollection(array_map(
$creation->deviceLongUrls,
fn (DeviceLongUrlPair $pair) => DeviceLongUrl::fromShortUrlAndPair($instance, $pair), fn (DeviceLongUrlPair $pair) => DeviceLongUrl::fromShortUrlAndPair($instance, $pair),
$creation->deviceLongUrls,
)); ));
$instance->tags = $relationResolver->resolveTags($creation->tags); $instance->tags = $relationResolver->resolveTags($creation->tags);
$instance->validSince = $creation->validSince; $instance->validSince = $creation->validSince;

View File

@@ -6,9 +6,7 @@ namespace Shlinkio\Shlink\Core\ShortUrl\Model;
use Shlinkio\Shlink\Core\Model\DeviceType; use Shlinkio\Shlink\Core\Model\DeviceType;
use function array_values;
use function Functional\group; use function Functional\group;
use function Functional\map;
use function trim; use function trim;
final class DeviceLongUrlPair final class DeviceLongUrlPair
@@ -32,15 +30,23 @@ final class DeviceLongUrlPair
*/ */
public static function fromMapToChangeSet(array $map): array public static function fromMapToChangeSet(array $map): array
{ {
$toRemove = []; // TODO Use when group is removed
$toKeep = []; // TODO Use when group is removed
$typesWithNullUrl = group($map, static fn (?string $longUrl) => $longUrl === null ? 'remove' : 'keep'); $typesWithNullUrl = group($map, static fn (?string $longUrl) => $longUrl === null ? 'remove' : 'keep');
$deviceTypesToRemove = array_values(map(
$typesWithNullUrl['remove'] ?? [], $deviceTypesToRemove = [];
static fn ($_, string $deviceType) => DeviceType::from($deviceType), foreach ($typesWithNullUrl['remove'] ?? [] as $deviceType => $_) {
)); $deviceTypesToRemove[] = DeviceType::from($deviceType);
$pairsToKeep = map( }
$typesWithNullUrl['keep'] ?? [],
fn (string $longUrl, string $deviceType) => self::fromRawTypeAndLongUrl($deviceType, $longUrl), $pairsToKeep = [];
); /**
* @var string $deviceType
* @var string $longUrl
*/
foreach ($typesWithNullUrl['keep'] ?? [] as $deviceType => $longUrl) {
$pairsToKeep[$deviceType] = self::fromRawTypeAndLongUrl($deviceType, $longUrl);
}
return [$pairsToKeep, $deviceTypesToRemove]; return [$pairsToKeep, $deviceTypesToRemove];
} }

View File

@@ -15,9 +15,8 @@ use Symfony\Component\Lock\Lock;
use Symfony\Component\Lock\LockFactory; use Symfony\Component\Lock\LockFactory;
use Symfony\Component\Lock\Store\InMemoryStore; use Symfony\Component\Lock\Store\InMemoryStore;
use function Functional\invoke; use function array_map;
use function Functional\map; use function array_unique;
use function Functional\unique;
class PersistenceShortUrlRelationResolver implements ShortUrlRelationResolverInterface class PersistenceShortUrlRelationResolver implements ShortUrlRelationResolverInterface
{ {
@@ -74,10 +73,10 @@ class PersistenceShortUrlRelationResolver implements ShortUrlRelationResolverInt
return new Collections\ArrayCollection(); return new Collections\ArrayCollection();
} }
$tags = unique($tags); $tags = array_unique($tags);
$repo = $this->em->getRepository(Tag::class); $repo = $this->em->getRepository(Tag::class);
return new Collections\ArrayCollection(map($tags, function (string $tagName) use ($repo): Tag { return new Collections\ArrayCollection(array_map(function (string $tagName) use ($repo): Tag {
$this->lock($this->tagLocks, 'tag_' . $tagName); $this->lock($this->tagLocks, 'tag_' . $tagName);
$existingTag = $repo->findOneBy(['name' => $tagName]); $existingTag = $repo->findOneBy(['name' => $tagName]);
@@ -91,7 +90,7 @@ class PersistenceShortUrlRelationResolver implements ShortUrlRelationResolverInt
$this->em->persist($tag); $this->em->persist($tag);
return $tag; return $tag;
})); }, $tags));
} }
private function memoizeNewTag(string $tagName): Tag private function memoizeNewTag(string $tagName): Tag
@@ -110,6 +109,7 @@ class PersistenceShortUrlRelationResolver implements ShortUrlRelationResolverInt
$lock->acquire(true); $lock->acquire(true);
} }
/**
/** /**
* @param array<string, Lock> $locks * @param array<string, Lock> $locks
*/ */
@@ -126,9 +126,15 @@ class PersistenceShortUrlRelationResolver implements ShortUrlRelationResolverInt
$this->memoizedNewTags = []; $this->memoizedNewTags = [];
// Release all locks // Release all locks
invoke($this->tagLocks, 'release'); $this->releaseLocks($this->tagLocks);
invoke($this->domainLocks, 'release'); $this->releaseLocks($this->domainLocks);
$this->tagLocks = []; }
$this->domainLocks = [];
private function releaseLocks(array &$locks): void
{
foreach ($locks as $tagLock) {
$tagLock->release();
}
$locks = [];
} }
} }

View File

@@ -8,7 +8,7 @@ use Doctrine\Common\Collections;
use Shlinkio\Shlink\Core\Domain\Entity\Domain; use Shlinkio\Shlink\Core\Domain\Entity\Domain;
use Shlinkio\Shlink\Core\Tag\Entity\Tag; use Shlinkio\Shlink\Core\Tag\Entity\Tag;
use function Functional\map; use function array_map;
class SimpleShortUrlRelationResolver implements ShortUrlRelationResolverInterface class SimpleShortUrlRelationResolver implements ShortUrlRelationResolverInterface
{ {
@@ -23,6 +23,6 @@ class SimpleShortUrlRelationResolver implements ShortUrlRelationResolverInterfac
*/ */
public function resolveTags(array $tags): Collections\Collection public function resolveTags(array $tags): Collections\Collection
{ {
return new Collections\ArrayCollection(map($tags, fn (string $tag) => new Tag($tag))); return new Collections\ArrayCollection(array_map(fn (string $tag) => new Tag($tag), $tags));
} }
} }

View File

@@ -7,10 +7,10 @@ namespace Shlinkio\Shlink\Core\ShortUrl\Transformer;
use Shlinkio\Shlink\Common\Rest\DataTransformerInterface; use Shlinkio\Shlink\Common\Rest\DataTransformerInterface;
use Shlinkio\Shlink\Core\ShortUrl\Entity\ShortUrl; use Shlinkio\Shlink\Core\ShortUrl\Entity\ShortUrl;
use Shlinkio\Shlink\Core\ShortUrl\Helper\ShortUrlStringifierInterface; use Shlinkio\Shlink\Core\ShortUrl\Helper\ShortUrlStringifierInterface;
use Shlinkio\Shlink\Core\Tag\Entity\Tag;
use Shlinkio\Shlink\Core\Visit\Model\VisitsSummary; use Shlinkio\Shlink\Core\Visit\Model\VisitsSummary;
use function Functional\invoke; use function array_map;
use function Functional\invoke_if;
class ShortUrlDataTransformer implements DataTransformerInterface class ShortUrlDataTransformer implements DataTransformerInterface
{ {
@@ -29,7 +29,7 @@ class ShortUrlDataTransformer implements DataTransformerInterface
'longUrl' => $shortUrl->getLongUrl(), 'longUrl' => $shortUrl->getLongUrl(),
'deviceLongUrls' => $shortUrl->deviceLongUrls(), 'deviceLongUrls' => $shortUrl->deviceLongUrls(),
'dateCreated' => $shortUrl->getDateCreated()->toAtomString(), 'dateCreated' => $shortUrl->getDateCreated()->toAtomString(),
'tags' => invoke($shortUrl->getTags(), '__toString'), 'tags' => array_map(static fn (Tag $tag) => $tag->__toString(), $shortUrl->getTags()->toArray()),
'meta' => $this->buildMeta($shortUrl), 'meta' => $this->buildMeta($shortUrl),
'domain' => $shortUrl->getDomain(), 'domain' => $shortUrl->getDomain(),
'title' => $shortUrl->title(), 'title' => $shortUrl->title(),
@@ -52,8 +52,8 @@ class ShortUrlDataTransformer implements DataTransformerInterface
$maxVisits = $shortUrl->getMaxVisits(); $maxVisits = $shortUrl->getMaxVisits();
return [ return [
'validSince' => invoke_if($validSince, 'toAtomString'), 'validSince' => $validSince?->toAtomString(),
'validUntil' => invoke_if($validUntil, 'toAtomString'), 'validUntil' => $validUntil?->toAtomString(),
'maxVisits' => $maxVisits, 'maxVisits' => $maxVisits,
]; ];
} }

View File

@@ -17,8 +17,8 @@ use Shlinkio\Shlink\Rest\ApiKey\Role;
use Shlinkio\Shlink\Rest\ApiKey\Spec\WithApiKeySpecsEnsuringJoin; use Shlinkio\Shlink\Rest\ApiKey\Spec\WithApiKeySpecsEnsuringJoin;
use Shlinkio\Shlink\Rest\Entity\ApiKey; use Shlinkio\Shlink\Rest\Entity\ApiKey;
use function array_map;
use function Functional\each; use function Functional\each;
use function Functional\map;
use function Shlinkio\Shlink\Core\camelCaseToSnakeCase; use function Shlinkio\Shlink\Core\camelCaseToSnakeCase;
use const PHP_INT_MAX; use const PHP_INT_MAX;
@@ -126,9 +126,9 @@ class TagRepository extends EntitySpecificationRepository implements TagReposito
$rsm->addScalarResult('non_bot_visits', 'nonBotVisits'); $rsm->addScalarResult('non_bot_visits', 'nonBotVisits');
$rsm->addScalarResult('short_urls_count', 'shortUrlsCount'); $rsm->addScalarResult('short_urls_count', 'shortUrlsCount');
return map( return array_map(
$this->getEntityManager()->createNativeQuery($mainQb->getSQL(), $rsm)->getResult(),
TagInfo::fromRawData(...), TagInfo::fromRawData(...),
$this->getEntityManager()->createNativeQuery($mainQb->getSQL(), $rsm)->getResult(),
); );
} }

View File

@@ -16,9 +16,9 @@ use Shlinkio\Shlink\Core\Options\TrackingOptions;
use Shlinkio\Shlink\Core\ShortUrl\Entity\ShortUrl; use Shlinkio\Shlink\Core\ShortUrl\Entity\ShortUrl;
use Shlinkio\Shlink\Core\Visit\Model\Visitor; use Shlinkio\Shlink\Core\Visit\Model\Visitor;
use function array_keys;
use function array_map;
use function explode; use function explode;
use function Functional\map;
use function Functional\some;
use function implode; use function implode;
use function str_contains; use function str_contains;
@@ -85,22 +85,30 @@ class RequestTracker implements RequestTrackerInterface, RequestMethodInterface
$remoteAddrParts = explode('.', $remoteAddr); $remoteAddrParts = explode('.', $remoteAddr);
$disableTrackingFrom = $this->trackingOptions->disableTrackingFrom; $disableTrackingFrom = $this->trackingOptions->disableTrackingFrom;
return some($disableTrackingFrom, function (string $value) use ($ip, $remoteAddrParts): bool { foreach ($disableTrackingFrom as $value) {
$range = str_contains($value, '*') $range = str_contains($value, '*')
? $this->parseValueWithWildcards($value, $remoteAddrParts) ? $this->parseValueWithWildcards($value, $remoteAddrParts)
: Factory::parseRangeString($value); : Factory::parseRangeString($value);
return $range !== null && $ip->matches($range); if ($range !== null && $ip->matches($range)) {
}); return true;
}
}
return false;
} }
private function parseValueWithWildcards(string $value, array $remoteAddrParts): ?RangeInterface private function parseValueWithWildcards(string $value, array $remoteAddrParts): ?RangeInterface
{ {
$octets = explode('.', $value);
$keys = array_keys($octets);
// Replace wildcard parts with the corresponding ones from the remote address // Replace wildcard parts with the corresponding ones from the remote address
return Factory::parseRangeString( return Factory::parseRangeString(
implode('.', map( implode('.', array_map(
explode('.', $value),
fn (string $part, int $index) => $part === '*' ? $remoteAddrParts[$index] : $part, fn (string $part, int $index) => $part === '*' ? $remoteAddrParts[$index] : $part,
$octets,
$keys,
)), )),
); );
} }

View File

@@ -22,8 +22,8 @@ use Shlinkio\Shlink\Core\Visit\Entity\Visit;
use Shlinkio\Shlink\Core\Visit\Model\Visitor; use Shlinkio\Shlink\Core\Visit\Model\Visitor;
use Shlinkio\Shlink\TestUtils\DbTest\DatabaseTestCase; use Shlinkio\Shlink\TestUtils\DbTest\DatabaseTestCase;
use function array_map;
use function count; use function count;
use function Functional\map;
use function range; use function range;
class ShortUrlListRepositoryTest extends DatabaseTestCase class ShortUrlListRepositoryTest extends DatabaseTestCase
@@ -60,22 +60,22 @@ class ShortUrlListRepositoryTest extends DatabaseTestCase
$this->getEntityManager()->persist($foo); $this->getEntityManager()->persist($foo);
$bar = ShortUrl::withLongUrl('https://bar'); $bar = ShortUrl::withLongUrl('https://bar');
$visits = map(range(0, 5), function () use ($bar) { $visits = array_map(function () use ($bar) {
$visit = Visit::forValidShortUrl($bar, Visitor::botInstance()); $visit = Visit::forValidShortUrl($bar, Visitor::botInstance());
$this->getEntityManager()->persist($visit); $this->getEntityManager()->persist($visit);
return $visit; return $visit;
}); }, range(0, 5));
$bar->setVisits(new ArrayCollection($visits)); $bar->setVisits(new ArrayCollection($visits));
$this->getEntityManager()->persist($bar); $this->getEntityManager()->persist($bar);
$foo2 = ShortUrl::withLongUrl('https://foo_2'); $foo2 = ShortUrl::withLongUrl('https://foo_2');
$visits2 = map(range(0, 3), function () use ($foo2) { $visits2 = array_map(function () use ($foo2) {
$visit = Visit::forValidShortUrl($foo2, Visitor::emptyInstance()); $visit = Visit::forValidShortUrl($foo2, Visitor::emptyInstance());
$this->getEntityManager()->persist($visit); $this->getEntityManager()->persist($visit);
return $visit; return $visit;
}); }, range(0, 3));
$foo2->setVisits(new ArrayCollection($visits2)); $foo2->setVisits(new ArrayCollection($visits2));
$ref = new ReflectionObject($foo2); $ref = new ReflectionObject($foo2);
$dateProp = $ref->getProperty('dateCreated'); $dateProp = $ref->getProperty('dateCreated');

View File

@@ -12,7 +12,7 @@ use Shlinkio\Shlink\Core\Tag\Paginator\Adapter\TagsPaginatorAdapter;
use Shlinkio\Shlink\Core\Tag\Repository\TagRepository; use Shlinkio\Shlink\Core\Tag\Repository\TagRepository;
use Shlinkio\Shlink\TestUtils\DbTest\DatabaseTestCase; use Shlinkio\Shlink\TestUtils\DbTest\DatabaseTestCase;
use function Functional\map; use function array_map;
class TagsPaginatorAdapterTest extends DatabaseTestCase class TagsPaginatorAdapterTest extends DatabaseTestCase
{ {
@@ -47,7 +47,7 @@ class TagsPaginatorAdapterTest extends DatabaseTestCase
'orderBy' => $orderBy, 'orderBy' => $orderBy,
]), null); ]), null);
$tagNames = map($adapter->getSlice($offset, $length), static fn (Tag $tag) => $tag->__toString()); $tagNames = array_map(static fn (Tag $tag) => $tag->__toString(), [...$adapter->getSlice($offset, $length)]);
self::assertEquals($expectedTags, $tagNames); self::assertEquals($expectedTags, $tagNames);
self::assertEquals($expectedTotalCount, $adapter->getNbResults()); self::assertEquals($expectedTotalCount, $adapter->getNbResults());

View File

@@ -14,7 +14,7 @@ use Shlinkio\Shlink\Core\Visit\Repository\VisitLocationRepository;
use Shlinkio\Shlink\IpGeolocation\Model\Location; use Shlinkio\Shlink\IpGeolocation\Model\Location;
use Shlinkio\Shlink\TestUtils\DbTest\DatabaseTestCase; use Shlinkio\Shlink\TestUtils\DbTest\DatabaseTestCase;
use function Functional\map; use function array_map;
use function range; use function range;
class VisitLocationRepositoryTest extends DatabaseTestCase class VisitLocationRepositoryTest extends DatabaseTestCase
@@ -57,6 +57,6 @@ class VisitLocationRepositoryTest extends DatabaseTestCase
public static function provideBlockSize(): iterable public static function provideBlockSize(): iterable
{ {
return map(range(1, 10), fn (int $value) => [$value]); return array_map(static fn (int $value) => [$value], range(1, 10));
} }
} }

View File

@@ -16,7 +16,7 @@ use Shlinkio\Shlink\CLI\GeoLite\GeolocationResult;
use Shlinkio\Shlink\Core\EventDispatcher\Event\GeoLiteDbCreated; use Shlinkio\Shlink\Core\EventDispatcher\Event\GeoLiteDbCreated;
use Shlinkio\Shlink\Core\EventDispatcher\UpdateGeoLiteDb; use Shlinkio\Shlink\Core\EventDispatcher\UpdateGeoLiteDb;
use function Functional\map; use function array_map;
class UpdateGeoLiteDbTest extends TestCase class UpdateGeoLiteDbTest extends TestCase
{ {
@@ -124,9 +124,9 @@ class UpdateGeoLiteDbTest extends TestCase
public static function provideGeolocationResults(): iterable public static function provideGeolocationResults(): iterable
{ {
return map(GeolocationResult::cases(), static fn (GeolocationResult $value) => [ return array_map(static fn (GeolocationResult $value) => [
$value, $value,
$value === GeolocationResult::DB_CREATED ? 1 : 0, $value === GeolocationResult::DB_CREATED ? 1 : 0,
]); ], GeolocationResult::cases());
} }
} }

View File

@@ -10,7 +10,7 @@ use PHPUnit\Framework\TestCase;
use Shlinkio\Shlink\Core\Exception\DeleteShortUrlException; use Shlinkio\Shlink\Core\Exception\DeleteShortUrlException;
use Shlinkio\Shlink\Core\ShortUrl\Model\ShortUrlIdentifier; use Shlinkio\Shlink\Core\ShortUrl\Model\ShortUrlIdentifier;
use function Functional\map; use function array_map;
use function range; use function range;
use function Shlinkio\Shlink\Core\generateRandomShortCode; use function Shlinkio\Shlink\Core\generateRandomShortCode;
use function sprintf; use function sprintf;
@@ -42,13 +42,13 @@ class DeleteShortUrlExceptionTest extends TestCase
public static function provideThresholds(): array public static function provideThresholds(): array
{ {
return map(range(5, 50, 5), function (int $number) { return array_map(function (int $number) {
return [$number, $shortCode = generateRandomShortCode(6), sprintf( return [$number, $shortCode = generateRandomShortCode(6), sprintf(
'Impossible to delete short URL with short code "%s", since it has more than "%s" visits.', 'Impossible to delete short URL with short code "%s", since it has more than "%s" visits.',
$shortCode, $shortCode,
$number, $number,
)]; )];
}); }, range(5, 50, 5));
} }
#[Test] #[Test]

View File

@@ -13,7 +13,7 @@ use Shlinkio\Shlink\Core\Model\DeviceType;
use Shlinkio\Shlink\Core\ShortUrl\Model\OrderableField; use Shlinkio\Shlink\Core\ShortUrl\Model\OrderableField;
use Shlinkio\Shlink\Core\Visit\Model\VisitType; use Shlinkio\Shlink\Core\Visit\Model\VisitType;
use function Functional\map; use function array_map;
use function Shlinkio\Shlink\Core\enumValues; use function Shlinkio\Shlink\Core\enumValues;
class FunctionsTest extends TestCase class FunctionsTest extends TestCase
@@ -29,18 +29,21 @@ class FunctionsTest extends TestCase
public static function provideEnums(): iterable public static function provideEnums(): iterable
{ {
yield EnvVars::class => [EnvVars::class, map(EnvVars::cases(), static fn (EnvVars $envVar) => $envVar->value)]; yield EnvVars::class => [
EnvVars::class,
array_map(static fn (EnvVars $envVar) => $envVar->value, EnvVars::cases()),
];
yield VisitType::class => [ yield VisitType::class => [
VisitType::class, VisitType::class,
map(VisitType::cases(), static fn (VisitType $envVar) => $envVar->value), array_map(static fn (VisitType $envVar) => $envVar->value, VisitType::cases()),
]; ];
yield DeviceType::class => [ yield DeviceType::class => [
DeviceType::class, DeviceType::class,
map(DeviceType::cases(), static fn (DeviceType $envVar) => $envVar->value), array_map(static fn (DeviceType $envVar) => $envVar->value, DeviceType::cases()),
]; ];
yield OrderableField::class => [ yield OrderableField::class => [
OrderableField::class, OrderableField::class,
map(OrderableField::cases(), static fn (OrderableField $envVar) => $envVar->value), array_map(static fn (OrderableField $envVar) => $envVar->value, OrderableField::cases()),
]; ];
} }
} }

View File

@@ -18,7 +18,7 @@ use Shlinkio\Shlink\Core\ShortUrl\ShortUrlResolverInterface;
use Shlinkio\Shlink\Core\Visit\Entity\Visit; use Shlinkio\Shlink\Core\Visit\Entity\Visit;
use Shlinkio\Shlink\Core\Visit\Model\Visitor; use Shlinkio\Shlink\Core\Visit\Model\Visitor;
use function Functional\map; use function array_map;
use function range; use function range;
use function sprintf; use function sprintf;
@@ -31,7 +31,7 @@ class DeleteShortUrlServiceTest extends TestCase
protected function setUp(): void protected function setUp(): void
{ {
$shortUrl = ShortUrl::createFake()->setVisits(new ArrayCollection( $shortUrl = ShortUrl::createFake()->setVisits(new ArrayCollection(
map(range(0, 10), fn () => Visit::forValidShortUrl(ShortUrl::createFake(), Visitor::emptyInstance())), array_map(fn () => Visit::forValidShortUrl(ShortUrl::createFake(), Visitor::emptyInstance()), range(0, 10)),
)); ));
$this->shortCode = $shortUrl->getShortCode(); $this->shortCode = $shortUrl->getShortCode();

View File

@@ -19,8 +19,8 @@ use Shlinkio\Shlink\Core\ShortUrl\Model\Validation\ShortUrlInputFilter;
use Shlinkio\Shlink\Importer\Model\ImportedShlinkUrl; use Shlinkio\Shlink\Importer\Model\ImportedShlinkUrl;
use Shlinkio\Shlink\Importer\Sources\ImportSource; use Shlinkio\Shlink\Importer\Sources\ImportSource;
use function array_map;
use function Functional\every; use function Functional\every;
use function Functional\map;
use function range; use function range;
use function strlen; use function strlen;
use function strtolower; use function strtolower;
@@ -88,7 +88,7 @@ class ShortUrlTest extends TestCase
public static function provideLengths(): iterable public static function provideLengths(): iterable
{ {
yield [null, DEFAULT_SHORT_CODES_LENGTH]; yield [null, DEFAULT_SHORT_CODES_LENGTH];
yield from map(range(4, 10), fn (int $value) => [$value, $value]); yield from array_map(fn (int $value) => [$value, $value], range(4, 10));
} }
#[Test] #[Test]

View File

@@ -25,7 +25,7 @@ use Shlinkio\Shlink\Core\Visit\Model\Visitor;
use Shlinkio\Shlink\Rest\Entity\ApiKey; use Shlinkio\Shlink\Rest\Entity\ApiKey;
use ShlinkioTest\Shlink\Core\Util\ApiKeyDataProviders; use ShlinkioTest\Shlink\Core\Util\ApiKeyDataProviders;
use function Functional\map; use function array_map;
use function range; use function range;
class ShortUrlResolverTest extends TestCase class ShortUrlResolverTest extends TestCase
@@ -113,9 +113,9 @@ class ShortUrlResolverTest extends TestCase
$shortUrl = ShortUrl::create( $shortUrl = ShortUrl::create(
ShortUrlCreation::fromRawData(['maxVisits' => 3, 'longUrl' => 'https://longUrl']), ShortUrlCreation::fromRawData(['maxVisits' => 3, 'longUrl' => 'https://longUrl']),
); );
$shortUrl->setVisits(new ArrayCollection(map( $shortUrl->setVisits(new ArrayCollection(array_map(
range(0, 4),
fn () => Visit::forValidShortUrl($shortUrl, Visitor::emptyInstance()), fn () => Visit::forValidShortUrl($shortUrl, Visitor::emptyInstance()),
range(0, 4),
))); )));
return $shortUrl; return $shortUrl;
@@ -132,9 +132,9 @@ class ShortUrlResolverTest extends TestCase
'validUntil' => $now->subMonths(1)->toAtomString(), 'validUntil' => $now->subMonths(1)->toAtomString(),
'longUrl' => 'https://longUrl', 'longUrl' => 'https://longUrl',
])); ]));
$shortUrl->setVisits(new ArrayCollection(map( $shortUrl->setVisits(new ArrayCollection(array_map(
range(0, 4),
fn () => Visit::forValidShortUrl($shortUrl, Visitor::emptyInstance()), fn () => Visit::forValidShortUrl($shortUrl, Visitor::emptyInstance()),
range(0, 4),
))); )));
return $shortUrl; return $shortUrl;

View File

@@ -84,4 +84,14 @@ class ShortUrlDataTransformerTest extends TestCase
], ],
]; ];
} }
#[Test]
public function properTagsAreReturned(): void
{
['tags' => $tags] = $this->transformer->transform(ShortUrl::create(ShortUrlCreation::fromRawData([
'longUrl' => 'https://longUrl',
'tags' => ['foo', 'bar', 'baz'],
])));
self::assertEquals(['foo', 'bar', 'baz'], $tags);
}
} }

View File

@@ -20,9 +20,9 @@ use Shlinkio\Shlink\Core\Visit\Model\Visitor;
use Shlinkio\Shlink\Core\Visit\Repository\VisitLocationRepositoryInterface; use Shlinkio\Shlink\Core\Visit\Repository\VisitLocationRepositoryInterface;
use Shlinkio\Shlink\IpGeolocation\Model\Location; use Shlinkio\Shlink\IpGeolocation\Model\Location;
use function array_map;
use function count; use function count;
use function floor; use function floor;
use function Functional\map;
use function range; use function range;
use function sprintf; use function sprintf;
@@ -45,12 +45,12 @@ class VisitLocatorTest extends TestCase
string $serviceMethodName, string $serviceMethodName,
string $expectedRepoMethodName, string $expectedRepoMethodName,
): void { ): void {
$unlocatedVisits = map( $unlocatedVisits = array_map(
range(1, 200),
fn (int $i) => Visit::forValidShortUrl( fn (int $i) => Visit::forValidShortUrl(
ShortUrl::withLongUrl(sprintf('https://short_code_%s', $i)), ShortUrl::withLongUrl(sprintf('https://short_code_%s', $i)),
Visitor::emptyInstance(), Visitor::emptyInstance(),
), ),
range(1, 200),
); );
$this->repo->expects($this->once())->method($expectedRepoMethodName)->willReturn($unlocatedVisits); $this->repo->expects($this->once())->method($expectedRepoMethodName)->willReturn($unlocatedVisits);

View File

@@ -33,8 +33,8 @@ use Shlinkio\Shlink\Core\Visit\VisitsStatsHelper;
use Shlinkio\Shlink\Rest\Entity\ApiKey; use Shlinkio\Shlink\Rest\Entity\ApiKey;
use ShlinkioTest\Shlink\Core\Util\ApiKeyDataProviders; use ShlinkioTest\Shlink\Core\Util\ApiKeyDataProviders;
use function array_map;
use function count; use function count;
use function Functional\map;
use function range; use function range;
class VisitsStatsHelperTest extends TestCase class VisitsStatsHelperTest extends TestCase
@@ -75,8 +75,8 @@ class VisitsStatsHelperTest extends TestCase
public static function provideCounts(): iterable public static function provideCounts(): iterable
{ {
return [ return [
...map(range(0, 50, 5), fn (int $value) => [$value, null]), ...array_map(fn (int $value) => [$value, null], range(0, 50, 5)),
...map(range(0, 18, 3), fn (int $value) => [$value, ApiKey::create()]), ...array_map(fn (int $value) => [$value, ApiKey::create()], range(0, 18, 3)),
]; ];
} }
@@ -90,7 +90,10 @@ class VisitsStatsHelperTest extends TestCase
$repo = $this->createMock(ShortUrlRepositoryInterface::class); $repo = $this->createMock(ShortUrlRepositoryInterface::class);
$repo->expects($this->once())->method('shortCodeIsInUse')->with($identifier, $spec)->willReturn(true); $repo->expects($this->once())->method('shortCodeIsInUse')->with($identifier, $spec)->willReturn(true);
$list = map(range(0, 1), fn () => Visit::forValidShortUrl(ShortUrl::createFake(), Visitor::emptyInstance())); $list = array_map(
static fn () => Visit::forValidShortUrl(ShortUrl::createFake(), Visitor::emptyInstance()),
range(0, 1),
);
$repo2 = $this->createMock(VisitRepository::class); $repo2 = $this->createMock(VisitRepository::class);
$repo2->method('findVisitsByShortCode')->with( $repo2->method('findVisitsByShortCode')->with(
$identifier, $identifier,
@@ -147,7 +150,10 @@ class VisitsStatsHelperTest extends TestCase
$repo = $this->createMock(TagRepository::class); $repo = $this->createMock(TagRepository::class);
$repo->expects($this->once())->method('tagExists')->with($tag, $apiKey)->willReturn(true); $repo->expects($this->once())->method('tagExists')->with($tag, $apiKey)->willReturn(true);
$list = map(range(0, 1), fn () => Visit::forValidShortUrl(ShortUrl::createFake(), Visitor::emptyInstance())); $list = array_map(
static fn () => Visit::forValidShortUrl(ShortUrl::createFake(), Visitor::emptyInstance()),
range(0, 1),
);
$repo2 = $this->createMock(VisitRepository::class); $repo2 = $this->createMock(VisitRepository::class);
$repo2->method('findVisitsByTag')->with($tag, $this->isInstanceOf(VisitsListFiltering::class))->willReturn( $repo2->method('findVisitsByTag')->with($tag, $this->isInstanceOf(VisitsListFiltering::class))->willReturn(
$list, $list,
@@ -185,7 +191,10 @@ class VisitsStatsHelperTest extends TestCase
$repo = $this->createMock(DomainRepository::class); $repo = $this->createMock(DomainRepository::class);
$repo->expects($this->once())->method('domainExists')->with($domain, $apiKey)->willReturn(true); $repo->expects($this->once())->method('domainExists')->with($domain, $apiKey)->willReturn(true);
$list = map(range(0, 1), fn () => Visit::forValidShortUrl(ShortUrl::createFake(), Visitor::emptyInstance())); $list = array_map(
static fn () => Visit::forValidShortUrl(ShortUrl::createFake(), Visitor::emptyInstance()),
range(0, 1),
);
$repo2 = $this->createMock(VisitRepository::class); $repo2 = $this->createMock(VisitRepository::class);
$repo2->method('findVisitsByDomain')->with( $repo2->method('findVisitsByDomain')->with(
$domain, $domain,
@@ -212,7 +221,10 @@ class VisitsStatsHelperTest extends TestCase
$repo = $this->createMock(DomainRepository::class); $repo = $this->createMock(DomainRepository::class);
$repo->expects($this->never())->method('domainExists'); $repo->expects($this->never())->method('domainExists');
$list = map(range(0, 1), fn () => Visit::forValidShortUrl(ShortUrl::createFake(), Visitor::emptyInstance())); $list = array_map(
static fn () => Visit::forValidShortUrl(ShortUrl::createFake(), Visitor::emptyInstance()),
range(0, 1),
);
$repo2 = $this->createMock(VisitRepository::class); $repo2 = $this->createMock(VisitRepository::class);
$repo2->method('findVisitsByDomain')->with( $repo2->method('findVisitsByDomain')->with(
'DEFAULT', 'DEFAULT',
@@ -236,7 +248,7 @@ class VisitsStatsHelperTest extends TestCase
#[Test] #[Test]
public function orphanVisitsAreReturnedAsExpected(): void public function orphanVisitsAreReturnedAsExpected(): void
{ {
$list = map(range(0, 3), fn () => Visit::forBasePath(Visitor::emptyInstance())); $list = array_map(static fn () => Visit::forBasePath(Visitor::emptyInstance()), range(0, 3));
$repo = $this->createMock(VisitRepository::class); $repo = $this->createMock(VisitRepository::class);
$repo->expects($this->once())->method('countOrphanVisits')->with( $repo->expects($this->once())->method('countOrphanVisits')->with(
$this->isInstanceOf(VisitsCountFiltering::class), $this->isInstanceOf(VisitsCountFiltering::class),
@@ -254,7 +266,10 @@ class VisitsStatsHelperTest extends TestCase
#[Test] #[Test]
public function nonOrphanVisitsAreReturnedAsExpected(): void public function nonOrphanVisitsAreReturnedAsExpected(): void
{ {
$list = map(range(0, 3), fn () => Visit::forValidShortUrl(ShortUrl::createFake(), Visitor::emptyInstance())); $list = array_map(
static fn () => Visit::forValidShortUrl(ShortUrl::createFake(), Visitor::emptyInstance()),
range(0, 3),
);
$repo = $this->createMock(VisitRepository::class); $repo = $this->createMock(VisitRepository::class);
$repo->expects($this->once())->method('countNonOrphanVisits')->with( $repo->expects($this->once())->method('countNonOrphanVisits')->with(
$this->isInstanceOf(VisitsCountFiltering::class), $this->isInstanceOf(VisitsCountFiltering::class),

View File

@@ -11,7 +11,7 @@ use Shlinkio\Shlink\Common\Middleware\AccessLogMiddleware;
return [ return [
'access_logs' => [ 'access_logs' => [
'ignored_paths' => [ 'ignored_path_prefixes' => [
Action\HealthAction::ROUTE_PATH, Action\HealthAction::ROUTE_PATH,
], ],
], ],
@@ -20,7 +20,7 @@ return [
ConfigAbstractFactory::class => [ ConfigAbstractFactory::class => [
// Use MergeReplaceKey to overwrite what was defined in shlink-common, instead of merging it // Use MergeReplaceKey to overwrite what was defined in shlink-common, instead of merging it
AccessLogMiddleware::class => new MergeReplaceKey( AccessLogMiddleware::class => new MergeReplaceKey(
[AccessLogMiddleware::LOGGER_SERVICE_NAME, 'config.access_logs.ignored_paths'], [AccessLogMiddleware::LOGGER_SERVICE_NAME, 'config.access_logs.ignored_path_prefixes'],
), ),
], ],

View File

@@ -14,7 +14,7 @@ use Shlinkio\Shlink\Core\Tag\TagServiceInterface;
use Shlinkio\Shlink\Rest\Action\AbstractRestAction; use Shlinkio\Shlink\Rest\Action\AbstractRestAction;
use Shlinkio\Shlink\Rest\Middleware\AuthenticationMiddleware; use Shlinkio\Shlink\Rest\Middleware\AuthenticationMiddleware;
use function Functional\map; use function array_map;
class ListTagsAction extends AbstractRestAction class ListTagsAction extends AbstractRestAction
{ {
@@ -41,7 +41,7 @@ class ListTagsAction extends AbstractRestAction
// This part is deprecated. To get tags with stats, the /tags/stats endpoint should be used instead // This part is deprecated. To get tags with stats, the /tags/stats endpoint should be used instead
$tagsInfo = $this->tagService->tagsInfo($params, $apiKey); $tagsInfo = $this->tagService->tagsInfo($params, $apiKey);
$rawTags = $this->serializePaginator($tagsInfo, dataProp: 'stats'); $rawTags = $this->serializePaginator($tagsInfo, dataProp: 'stats');
$rawTags['data'] = map($tagsInfo, static fn (TagInfo $info) => $info->tag); $rawTags['data'] = array_map(static fn (TagInfo $info) => $info->tag, [...$tagsInfo]);
return new JsonResponse(['tags' => $rawTags]); return new JsonResponse(['tags' => $rawTags]);
} }

View File

@@ -4,8 +4,8 @@ declare(strict_types=1);
namespace Shlinkio\Shlink\Rest; namespace Shlinkio\Shlink\Rest;
use function array_map;
use function Functional\first; use function Functional\first;
use function Functional\map;
use function Shlinkio\Shlink\Config\loadConfigFromGlob; use function Shlinkio\Shlink\Config\loadConfigFromGlob;
use function sprintf; use function sprintf;
@@ -23,11 +23,11 @@ class ConfigProvider
public static function applyRoutesPrefix(array $routes): array public static function applyRoutesPrefix(array $routes): array
{ {
$healthRoute = self::buildUnversionedHealthRouteFromExistingRoutes($routes); $healthRoute = self::buildUnversionedHealthRouteFromExistingRoutes($routes);
$prefixedRoutes = map($routes, static function (array $route) { $prefixedRoutes = array_map(static function (array $route) {
['path' => $path] = $route; ['path' => $path] = $route;
$route['path'] = sprintf('%s%s', self::ROUTES_PREFIX, $path); $route['path'] = sprintf('%s%s', self::ROUTES_PREFIX, $path);
return $route; return $route;
}); }, $routes);
return $healthRoute !== null ? [...$prefixedRoutes, $healthRoute] : $prefixedRoutes; return $healthRoute !== null ? [...$prefixedRoutes, $healthRoute] : $prefixedRoutes;
} }

View File

@@ -10,7 +10,7 @@ use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\Test; use PHPUnit\Framework\Attributes\Test;
use Shlinkio\Shlink\TestUtils\ApiTest\ApiTestCase; use Shlinkio\Shlink\TestUtils\ApiTest\ApiTestCase;
use function Functional\map; use function array_map;
use function range; use function range;
use function sprintf; use function sprintf;
@@ -108,7 +108,7 @@ class CreateShortUrlTest extends ApiTestCase
public static function provideMaxVisits(): array public static function provideMaxVisits(): array
{ {
return map(range(10, 15), fn(int $i) => [$i]); return array_map(static fn (int $i) => [$i], range(10, 15));
} }
#[Test] #[Test]