diff --git a/module/CLI/src/Command/Api/GenerateKeyCommand.php b/module/CLI/src/Command/Api/GenerateKeyCommand.php index 2dc91c51..119fa020 100644 --- a/module/CLI/src/Command/Api/GenerateKeyCommand.php +++ b/module/CLI/src/Command/Api/GenerateKeyCommand.php @@ -6,11 +6,11 @@ namespace Shlinkio\Shlink\CLI\Command\Api; use Cake\Chronos\Chronos; use Shlinkio\Shlink\CLI\ApiKey\RoleResolverInterface; +use Shlinkio\Shlink\CLI\Command\BaseCommand; use Shlinkio\Shlink\CLI\Util\ExitCodes; use Shlinkio\Shlink\CLI\Util\ShlinkTable; use Shlinkio\Shlink\Rest\ApiKey\Role; use Shlinkio\Shlink\Rest\Service\ApiKeyServiceInterface; -use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; @@ -19,7 +19,7 @@ use Symfony\Component\Console\Style\SymfonyStyle; use function Shlinkio\Shlink\Core\arrayToString; use function sprintf; -class GenerateKeyCommand extends Command +class GenerateKeyCommand extends BaseCommand { public const NAME = 'api-key:generate'; @@ -42,9 +42,9 @@ class GenerateKeyCommand extends Command %command.full_name% - You can optionally set its expiration date with --expirationDate or -e: + You can optionally set its expiration date with --expiration-date or -e: - %command.full_name% --expirationDate 2020-01-01 + %command.full_name% --expiration-date 2020-01-01 You can also set roles to the API key: @@ -56,8 +56,8 @@ class GenerateKeyCommand extends Command $this ->setName(self::NAME) ->setDescription('Generates a new valid API key.') - ->addOption( - 'expirationDate', + ->addOptionWithDeprecatedFallback( + 'expiration-date', 'e', InputOption::VALUE_REQUIRED, 'The date in which the API key should expire. Use any valid PHP format.', @@ -79,7 +79,7 @@ class GenerateKeyCommand extends Command protected function execute(InputInterface $input, OutputInterface $output): ?int { - $expirationDate = $input->getOption('expirationDate'); + $expirationDate = $this->getOptionWithDeprecatedFallback($input, 'expiration-date'); $apiKey = $this->apiKeyService->create( isset($expirationDate) ? Chronos::parse($expirationDate) : null, ...$this->roleResolver->determineRoles($input), diff --git a/module/CLI/src/Command/Api/ListKeysCommand.php b/module/CLI/src/Command/Api/ListKeysCommand.php index cf09e614..9243779b 100644 --- a/module/CLI/src/Command/Api/ListKeysCommand.php +++ b/module/CLI/src/Command/Api/ListKeysCommand.php @@ -4,12 +4,12 @@ declare(strict_types=1); namespace Shlinkio\Shlink\CLI\Command\Api; +use Shlinkio\Shlink\CLI\Command\BaseCommand; use Shlinkio\Shlink\CLI\Util\ExitCodes; use Shlinkio\Shlink\CLI\Util\ShlinkTable; use Shlinkio\Shlink\Rest\ApiKey\Role; use Shlinkio\Shlink\Rest\Entity\ApiKey; use Shlinkio\Shlink\Rest\Service\ApiKeyServiceInterface; -use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; @@ -19,7 +19,7 @@ use function Functional\map; use function implode; use function sprintf; -class ListKeysCommand extends Command +class ListKeysCommand extends BaseCommand { private const ERROR_STRING_PATTERN = '%s'; private const SUCCESS_STRING_PATTERN = '%s'; @@ -40,8 +40,8 @@ class ListKeysCommand extends Command $this ->setName(self::NAME) ->setDescription('Lists all the available API keys.') - ->addOption( - 'enabledOnly', + ->addOptionWithDeprecatedFallback( + 'enabled-only', 'e', InputOption::VALUE_NONE, 'Tells if only enabled API keys should be returned.', @@ -50,7 +50,7 @@ class ListKeysCommand extends Command protected function execute(InputInterface $input, OutputInterface $output): ?int { - $enabledOnly = $input->getOption('enabledOnly'); + $enabledOnly = $this->getOptionWithDeprecatedFallback($input, 'enabled-only'); $rows = map($this->apiKeyService->listKeys($enabledOnly), function (ApiKey $apiKey) use ($enabledOnly) { $expiration = $apiKey->getExpirationDate(); diff --git a/module/CLI/src/Command/BaseCommand.php b/module/CLI/src/Command/BaseCommand.php new file mode 100644 index 00000000..443b37ec --- /dev/null +++ b/module/CLI/src/Command/BaseCommand.php @@ -0,0 +1,51 @@ +addOption($name, $shortcut, $mode, $description, $default); + + if (str_contains($name, '-')) { + $camelCaseName = kebabCaseToCamelCase($name); + $this->addOption($camelCaseName, null, $mode, sprintf('[DEPRECATED] Same as "%s".', $name), $default); + } + + return $this; + } + + /** + * @return bool|string|string[]|null + */ + protected function getOptionWithDeprecatedFallback(InputInterface $input, string $name) + { + $rawInput = method_exists($input, '__toString') ? $input->__toString() : ''; + $camelCaseName = kebabCaseToCamelCase($name); + + if (str_contains($rawInput, $camelCaseName)) { + return $input->getOption($camelCaseName); + } + + return $input->getOption($name); + } +} diff --git a/module/CLI/src/Command/ShortUrl/GenerateShortUrlCommand.php b/module/CLI/src/Command/ShortUrl/GenerateShortUrlCommand.php index 12bbb3fb..7ceb0435 100644 --- a/module/CLI/src/Command/ShortUrl/GenerateShortUrlCommand.php +++ b/module/CLI/src/Command/ShortUrl/GenerateShortUrlCommand.php @@ -4,13 +4,13 @@ declare(strict_types=1); namespace Shlinkio\Shlink\CLI\Command\ShortUrl; +use Shlinkio\Shlink\CLI\Command\BaseCommand; use Shlinkio\Shlink\CLI\Util\ExitCodes; use Shlinkio\Shlink\Core\Exception\InvalidUrlException; use Shlinkio\Shlink\Core\Exception\NonUniqueSlugException; use Shlinkio\Shlink\Core\Model\ShortUrlMeta; use Shlinkio\Shlink\Core\Service\UrlShortenerInterface; use Shlinkio\Shlink\Core\Validation\ShortUrlMetaInputFilter; -use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; @@ -23,9 +23,9 @@ use function Functional\flatten; use function Functional\unique; use function method_exists; use function sprintf; -use function strpos; +use function str_contains; -class GenerateShortUrlCommand extends Command +class GenerateShortUrlCommand extends BaseCommand { public const NAME = 'short-url:generate'; @@ -53,34 +53,34 @@ class GenerateShortUrlCommand extends Command InputOption::VALUE_IS_ARRAY | InputOption::VALUE_REQUIRED, 'Tags to apply to the new short URL', ) - ->addOption( - 'validSince', + ->addOptionWithDeprecatedFallback( + 'valid-since', 's', InputOption::VALUE_REQUIRED, 'The date from which this short URL will be valid. ' . 'If someone tries to access it before this date, it will not be found.', ) - ->addOption( - 'validUntil', + ->addOptionWithDeprecatedFallback( + 'valid-until', 'u', InputOption::VALUE_REQUIRED, 'The date until which this short URL will be valid. ' . 'If someone tries to access it after this date, it will not be found.', ) - ->addOption( - 'customSlug', + ->addOptionWithDeprecatedFallback( + 'custom-slug', 'c', InputOption::VALUE_REQUIRED, 'If provided, this slug will be used instead of generating a short code', ) - ->addOption( - 'maxVisits', + ->addOptionWithDeprecatedFallback( + 'max-visits', 'm', InputOption::VALUE_REQUIRED, 'This will limit the number of visits for this short URL.', ) - ->addOption( - 'findIfExists', + ->addOptionWithDeprecatedFallback( + 'find-if-exists', 'f', InputOption::VALUE_NONE, 'This will force existing matching URL to be returned if found, instead of creating a new one.', @@ -91,11 +91,11 @@ class GenerateShortUrlCommand extends Command InputOption::VALUE_REQUIRED, 'The domain to which this short URL will be attached.', ) - ->addOption( - 'shortCodeLength', + ->addOptionWithDeprecatedFallback( + 'short-code-length', 'l', InputOption::VALUE_REQUIRED, - 'The length for generated short code (it will be ignored if --customSlug was provided).', + 'The length for generated short code (it will be ignored if --custom-slug was provided).', ) ->addOption( 'validate-url', @@ -136,18 +136,24 @@ class GenerateShortUrlCommand extends Command $explodeWithComma = curry('explode')(','); $tags = unique(flatten(array_map($explodeWithComma, $input->getOption('tags')))); - $customSlug = $input->getOption('customSlug'); - $maxVisits = $input->getOption('maxVisits'); - $shortCodeLength = $input->getOption('shortCodeLength') ?? $this->defaultShortCodeLength; + $customSlug = $this->getOptionWithDeprecatedFallback($input, 'custom-slug'); + $maxVisits = $this->getOptionWithDeprecatedFallback($input, 'max-visits'); + $shortCodeLength = $this->getOptionWithDeprecatedFallback( + $input, + 'short-code-length', + ) ?? $this->defaultShortCodeLength; $doValidateUrl = $this->doValidateUrl($input); try { $shortUrl = $this->urlShortener->shorten($longUrl, $tags, ShortUrlMeta::fromRawData([ - ShortUrlMetaInputFilter::VALID_SINCE => $input->getOption('validSince'), - ShortUrlMetaInputFilter::VALID_UNTIL => $input->getOption('validUntil'), + ShortUrlMetaInputFilter::VALID_SINCE => $this->getOptionWithDeprecatedFallback($input, 'valid-since'), + ShortUrlMetaInputFilter::VALID_UNTIL => $this->getOptionWithDeprecatedFallback($input, 'valid-until'), ShortUrlMetaInputFilter::CUSTOM_SLUG => $customSlug, ShortUrlMetaInputFilter::MAX_VISITS => $maxVisits !== null ? (int) $maxVisits : null, - ShortUrlMetaInputFilter::FIND_IF_EXISTS => $input->getOption('findIfExists'), + ShortUrlMetaInputFilter::FIND_IF_EXISTS => $this->getOptionWithDeprecatedFallback( + $input, + 'find-if-exists', + ), ShortUrlMetaInputFilter::DOMAIN => $input->getOption('domain'), ShortUrlMetaInputFilter::SHORT_CODE_LENGTH => $shortCodeLength, ShortUrlMetaInputFilter::VALIDATE_URL => $doValidateUrl, @@ -168,10 +174,10 @@ class GenerateShortUrlCommand extends Command { $rawInput = method_exists($input, '__toString') ? $input->__toString() : ''; - if (strpos($rawInput, '--no-validate-url') !== false) { + if (str_contains($rawInput, '--no-validate-url')) { return false; } - if (strpos($rawInput, '--validate-url') !== false) { + if (str_contains($rawInput, '--validate-url')) { return true; } diff --git a/module/Core/functions/functions.php b/module/Core/functions/functions.php index 076de6a0..531f8038 100644 --- a/module/Core/functions/functions.php +++ b/module/Core/functions/functions.php @@ -12,9 +12,12 @@ use PUGX\Shortid\Factory as ShortIdFactory; use function Functional\reduce_left; use function is_array; +use function lcfirst; use function print_r; use function sprintf; use function str_repeat; +use function str_replace; +use function ucwords; const DEFAULT_DELETE_SHORT_URL_THRESHOLD = 15; const DEFAULT_SHORT_CODES_LENGTH = 5; @@ -97,3 +100,8 @@ function arrayToString(array $array, int $indentSize = 4): string ); }, ''); } + +function kebabCaseToCamelCase(string $name): string +{ + return lcfirst(str_replace(' ', '', ucwords(str_replace('-', ' ', $name)))); +}