Release 2.20.0 (#4987)

This commit is contained in:
Kevin Papst
2024-08-04 18:22:27 +02:00
committed by GitHub
parent 0947b88d36
commit ff6a3e8262
101 changed files with 441 additions and 458 deletions

View File

@@ -2,7 +2,6 @@
ServerAdmin webmaster@localhost
DocumentRoot /opt/kimai/public
PassEnv DATABASE_PREFIX
PassEnv MAILER_FROM
PassEnv APP_ENV
PassEnv APP_SECRET

View File

@@ -21,8 +21,6 @@ version-resolver:
- 'translation'
default: patch
template: |
[Upgrade Kimai](https://www.kimai.org/documentation/updates.html) - [Install Kimai](https://www.kimai.org/documentation/installation.html) - [Docker](https://www.kimai.org/documentation/docker.html)
**Compatible with PHP 8.1 to 8.3**
$CHANGES

View File

@@ -66,7 +66,6 @@
"symfony/security-bundle": "^6.0",
"symfony/security-csrf": "^6.0",
"symfony/serializer": "^6.0",
"symfony/string": "v6.4.8",
"symfony/translation": "^6.0",
"symfony/twig-bundle": "^6.0",
"symfony/validator": "^6.0",

388
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -45,9 +45,9 @@ nelmio_api_doc:
- ^/api(?!/doc)
documentation:
info:
title: Kimai - API Docs
title: Kimai - API
description: |
JSON API for the Kimai time-tracking software: [API documentation](https://www.kimai.org/documentation/rest-api.html), [Swagger definition file](doc.json)
JSON API for the Kimai time-tracking software. Read our [API documentation](https://www.kimai.org/documentation/rest-api.html) and download the [Open API definition](doc.json) to import into your API client.
version: '1.0'
components:
securitySchemes:

View File

@@ -29,7 +29,6 @@ tabler:
routes:
tabler_welcome: dashboard
tabler_login: login
tabler_logout: logout
tabler_login_check: security_check
tabler_registration: registration_register
tabler_registration_register: registration_register

View File

@@ -278,11 +278,6 @@ parameters:
count: 1
path: src/Command/DemoteUserCommand.php
-
message: "#^Argument of an invalid type mixed supplied for foreach, only iterables are supported\\.$#"
count: 1
path: src/Command/ExportCreateCommand.php
-
message: "#^Binary operation \"\\.\" between non\\-falsy\\-string and non\\-empty\\-list\\<string\\>\\|string results in an error\\.$#"
count: 2
@@ -345,12 +340,7 @@ parameters:
-
message: "#^Parameter \\#1 \\$value of function count expects array\\|Countable, mixed given\\.$#"
count: 5
path: src/Command/ExportCreateCommand.php
-
message: "#^Parameter \\#1 \\.\\.\\.\\$addresses of method Symfony\\\\Component\\\\Mime\\\\Email\\:\\:addTo\\(\\) expects string\\|Symfony\\\\Component\\\\Mime\\\\Address, mixed given\\.$#"
count: 1
count: 4
path: src/Command/ExportCreateCommand.php
-
@@ -3268,36 +3258,6 @@ parameters:
count: 1
path: src/Form/Type/CustomerType.php
-
message: "#^Parameter \\#1 \\$inputTimezone of class Symfony\\\\Component\\\\Form\\\\Extension\\\\Core\\\\DataTransformer\\\\DateTimeToLocalizedStringTransformer constructor expects string\\|null, mixed given\\.$#"
count: 2
path: src/Form/Type/DateRangeType.php
-
message: "#^Parameter \\#1 \\$separator of function explode expects non\\-empty\\-string, mixed given\\.$#"
count: 1
path: src/Form/Type/DateRangeType.php
-
message: "#^Parameter \\#2 \\$outputTimezone of class Symfony\\\\Component\\\\Form\\\\Extension\\\\Core\\\\DataTransformer\\\\DateTimeToLocalizedStringTransformer constructor expects string\\|null, mixed given\\.$#"
count: 2
path: src/Form/Type/DateRangeType.php
-
message: "#^Parameter \\#4 \\$timezone of class IntlDateFormatter constructor expects DateTimeZone\\|IntlTimeZone\\|string\\|null, mixed given\\.$#"
count: 1
path: src/Form/Type/DateRangeType.php
-
message: "#^Parameter \\#6 \\$pattern of class IntlDateFormatter constructor expects string\\|null, mixed given\\.$#"
count: 1
path: src/Form/Type/DateRangeType.php
-
message: "#^Parameter \\#6 \\$pattern of class Symfony\\\\Component\\\\Form\\\\Extension\\\\Core\\\\DataTransformer\\\\DateTimeToLocalizedStringTransformer constructor expects string\\|null, mixed given\\.$#"
count: 1
path: src/Form/Type/DateRangeType.php
-
message: "#^Parameter \\#1 \\$inputTimezone of class Symfony\\\\Component\\\\Form\\\\Extension\\\\Core\\\\DataTransformer\\\\DateTimeToArrayTransformer constructor expects string\\|null, mixed given\\.$#"
count: 1

View File

@@ -72,7 +72,7 @@ abstract class AbstractBundleInstallerCommand extends Command
*/
protected function getInstallerCommandName(): string
{
return sprintf('kimai:bundle:%s:install', $this->getBundleCommandNamePart());
return \sprintf('kimai:bundle:%s:install', $this->getBundleCommandNamePart());
}
/**
@@ -87,7 +87,7 @@ abstract class AbstractBundleInstallerCommand extends Command
if ($parts[0] !== 'KimaiPlugin') {
throw new LogicException(
sprintf('Unsupported namespace given, expected "KimaiPlugin" but received "%s". Please overwrite getBundleName() and return the correct bundle name.', $parts[0])
\sprintf('Unsupported namespace given, expected "KimaiPlugin" but received "%s". Please overwrite getBundleName() and return the correct bundle name.', $parts[0])
);
}
@@ -114,14 +114,14 @@ abstract class AbstractBundleInstallerCommand extends Command
$bundleName = $this->getBundleName();
$io->title(
sprintf('Starting installation of plugin: %s ...', $bundleName)
\sprintf('Starting installation of plugin: %s ...', $bundleName)
);
try {
$this->importMigrations($io, $output);
} catch (\Exception $ex) {
$io->error(
sprintf('Failed to install database for bundle %s. %s', $bundleName, $ex->getMessage())
\sprintf('Failed to install database for bundle %s. %s', $bundleName, $ex->getMessage())
);
return Command::FAILURE;
@@ -132,7 +132,7 @@ abstract class AbstractBundleInstallerCommand extends Command
$this->installAssets($io, $output);
} catch (\Exception $ex) {
$io->error(
sprintf('Failed to install assets for bundle %s. %s', $bundleName, $ex->getMessage())
\sprintf('Failed to install assets for bundle %s. %s', $bundleName, $ex->getMessage())
);
return Command::FAILURE;
@@ -142,7 +142,7 @@ abstract class AbstractBundleInstallerCommand extends Command
chdir($path);
$io->success(
sprintf('Congratulations! Plugin was successful installed: %s', $bundleName)
\sprintf('Congratulations! Plugin was successful installed: %s', $bundleName)
);
return Command::SUCCESS;

View File

@@ -51,9 +51,9 @@ final class ActivateUserCommand extends Command
if (!$user->isEnabled()) {
$user->setEnabled(true);
$this->userService->saveUser($user);
$io->success(sprintf('User "%s" has been activated.', $username));
$io->success(\sprintf('User "%s" has been activated.', $username));
} else {
$io->warning(sprintf('User "%s" is already active.', $username));
$io->warning(\sprintf('User "%s" is already active.', $username));
}
return Command::SUCCESS;

View File

@@ -67,7 +67,7 @@ final class ChangePasswordCommand extends AbstractUserCommand
try {
$user->setPlainPassword($password);
$this->userService->updateUser($user, ['PasswordUpdate']);
$io->success(sprintf('Changed password for user "%s".', $username));
$io->success(\sprintf('Changed password for user "%s".', $username));
} catch (ValidationFailedException $ex) {
$this->validationError($ex, $io);

View File

@@ -77,7 +77,7 @@ final class CreateUserCommand extends AbstractUserCommand
try {
$this->userService->saveUser($user);
$io->success(sprintf('Success! Created user: %s', $username));
$io->success(\sprintf('Success! Created user: %s', $username));
} catch (ValidationFailedException $ex) {
$this->validationError($ex, $io);

View File

@@ -51,9 +51,9 @@ final class DeactivateUserCommand extends Command
if ($user->isEnabled()) {
$user->setEnabled(false);
$this->userService->saveUser($user);
$io->success(sprintf('User "%s" has been deactivated.', $username));
$io->success(\sprintf('User "%s" has been deactivated.', $username));
} else {
$io->warning(sprintf('User "%s" is already deactivated.', $username));
$io->warning(\sprintf('User "%s" is already deactivated.', $username));
}
return Command::SUCCESS;

View File

@@ -40,17 +40,17 @@ final class DemoteUserCommand extends AbstractRoleCommand
if ($user->isSuperAdmin()) {
$user->setSuperAdmin(false);
$userService->saveUser($user);
$output->success(sprintf('Super administrator role has been removed from the user "%s".', $username));
$output->success(\sprintf('Super administrator role has been removed from the user "%s".', $username));
} else {
$output->warning(sprintf('User "%s" doesn\'t have the super administrator role.', $username));
$output->warning(\sprintf('User "%s" doesn\'t have the super administrator role.', $username));
}
} else {
if ($user->hasRole($role)) {
$user->removeRole($role);
$userService->saveUser($user);
$output->success(sprintf('Role "%s" has been removed from user "%s".', $role, $username));
$output->success(\sprintf('Role "%s" has been removed from user "%s".', $role, $username));
} else {
$output->warning(sprintf('User "%s" didn\'t have "%s" role.', $username, $role));
$output->warning(\sprintf('User "%s" didn\'t have "%s" role.', $username, $role));
}
}
}

View File

@@ -35,13 +35,13 @@ use Symfony\Contracts\Translation\TranslatorInterface;
final class ExportCreateCommand extends Command
{
public function __construct(
private ServiceExport $serviceExport,
private CustomerRepository $customerRepository,
private ProjectRepository $projectRepository,
private TeamRepository $teamRepository,
private UserRepository $userRepository,
private TranslatorInterface $translator,
private MailerInterface $mailer
private readonly ServiceExport $serviceExport,
private readonly CustomerRepository $customerRepository,
private readonly ProjectRepository $projectRepository,
private readonly TeamRepository $teamRepository,
private readonly UserRepository $userRepository,
private readonly TranslatorInterface $translator,
private readonly MailerInterface $mailer
) {
parent::__construct();
}
@@ -197,17 +197,19 @@ final class ExportCreateCommand extends Command
$subject = 'Export data available';
$body = 'Your exported data is available, please find it attached to this email.';
/** @var array<string> $emails */
$emails = [];
/** @var array<string> $tmp */
$tmp = $input->getOption('email');
if (\count($tmp) > 0) {
foreach ($tmp as $email) {
$result = filter_var($email, FILTER_VALIDATE_EMAIL);
if ($result === false) {
$io->error('Invalid "email" given: ' . $email);
$io->error('Invalid "email" given');
return Command::FAILURE;
}
$emails[] = $email;
$emails[] = (string) $email;
}
}
@@ -227,7 +229,7 @@ final class ExportCreateCommand extends Command
$user = $this->userRepository->loadUserByIdentifier($username);
} catch(\Exception) {
$io->error(
sprintf('The given username "%s" could not be resolved', $username)
\sprintf('The given username "%s" could not be resolved', $username)
);
return Command::FAILURE;

View File

@@ -73,7 +73,7 @@ final class InstallCommand extends Command
}
$io->success(
sprintf('Congratulations! Successfully installed %s version %s', Constants::SOFTWARE, Constants::VERSION)
\sprintf('Congratulations! Successfully installed %s version %s', Constants::SOFTWARE, Constants::VERSION)
);
return Command::SUCCESS;
@@ -118,12 +118,12 @@ final class InstallCommand extends Command
{
try {
if ($this->connection->isConnected()) {
$io->note(sprintf('Database is existing and connection could be established'));
$io->note(\sprintf('Database is existing and connection could be established'));
return;
}
if (!$this->askConfirmation($input, $output, sprintf('Create the database "%s" (yes) or skip (no)?', $this->connection->getDatabase()), true)) {
if (!$this->askConfirmation($input, $output, \sprintf('Create the database "%s" (yes) or skip (no)?', $this->connection->getDatabase()), true)) {
throw new \Exception('Skipped database creation, aborting installation');
}
} catch (\Exception $exception) {
@@ -152,7 +152,7 @@ final class InstallCommand extends Command
{
/** @var QuestionHelper $questionHelper */
$questionHelper = $this->getHelperSet()->get('question');
$text = sprintf('<info>%s (yes/no)</info> [<comment>%s</comment>]:', $question, $default ? 'yes' : 'no');
$text = \sprintf('<info>%s (yes/no)</info> [<comment>%s</comment>]:', $question, $default ? 'yes' : 'no');
$question = new ConfirmationQuestion(' ' . $text . ' ', $default, '/^y|yes/i');
return $questionHelper->ask($input, $output, $question);

View File

@@ -90,7 +90,7 @@ final class InvoiceCreateCommand extends Command
$user = $this->userRepository->loadUserByIdentifier($username);
} catch (\Exception $exception) {
$io->error(
sprintf('The given username "%s" could not be resolved', $username)
\sprintf('The given username "%s" could not be resolved', $username)
);
return Command::FAILURE;
@@ -281,7 +281,7 @@ final class InvoiceCreateCommand extends Command
$tpl = $this->getTemplateForCustomer($input, $customer);
if (null === $tpl) {
$io->warning(sprintf('Could not find invoice template for project "%s", skipping!', $project->getName()));
$io->warning(\sprintf('Could not find invoice template for project "%s", skipping!', $project->getName()));
continue;
}
$query->setTemplate($tpl);
@@ -293,7 +293,7 @@ final class InvoiceCreateCommand extends Command
$invoices[] = $this->serviceInvoice->createInvoice($this->serviceInvoice->createModel($query), $this->eventDispatcher);
}
} catch (\Exception $ex) {
$io->error(sprintf('Failed to create invoice for project "%s" with: %s', $project->getName(), $ex->getMessage()));
$io->error(\sprintf('Failed to create invoice for project "%s" with: %s', $project->getName(), $ex->getMessage()));
}
}
@@ -352,7 +352,7 @@ final class InvoiceCreateCommand extends Command
$tpl = $this->getTemplateForCustomer($input, $customer);
if (null === $tpl) {
$io->warning(sprintf('Could not find invoice template for customer "%s", skipping!', $customer->getName()));
$io->warning(\sprintf('Could not find invoice template for customer "%s", skipping!', $customer->getName()));
continue;
}
$query->setTemplate($tpl);
@@ -364,7 +364,7 @@ final class InvoiceCreateCommand extends Command
$invoices[] = $this->serviceInvoice->createInvoice($this->serviceInvoice->createModel($query), $this->eventDispatcher);
}
} catch (\Exception $ex) {
$io->error(sprintf('Failed to create invoice for customer "%s" with: %s', $customer->getName(), $ex->getMessage()));
$io->error(\sprintf('Failed to create invoice for customer "%s" with: %s', $customer->getName(), $ex->getMessage()));
}
}
@@ -391,7 +391,7 @@ final class InvoiceCreateCommand extends Command
$columns = ['Filename'];
$table = new Table($output);
$table->setHeaderTitle(sprintf('Created %s invoice(s)', \count($invoices)));
$table->setHeaderTitle(\sprintf('Created %s invoice(s)', \count($invoices)));
$table->setHeaders($columns);
foreach ($invoices as $invoiceFile) {
@@ -406,14 +406,14 @@ final class InvoiceCreateCommand extends Command
$columns = ['ID', 'Customer', 'Total', 'Filename'];
$table = new Table($output);
$table->setHeaderTitle(sprintf('Created %s invoice(s)', \count($invoices)));
$table->setHeaderTitle(\sprintf('Created %s invoice(s)', \count($invoices)));
$table->setHeaders($columns);
foreach ($invoices as $invoice) {
$file = $this->serviceInvoice->getInvoiceFile($invoice);
if (null === $file) {
$io->warning(
sprintf('Created invoice with ID %s, but file was not found %s', $invoice->getId(), $invoice->getInvoiceFilename())
\sprintf('Created invoice with ID %s, but file was not found %s', $invoice->getId(), $invoice->getInvoiceFilename())
);
continue;
}

View File

@@ -40,17 +40,17 @@ final class PromoteUserCommand extends AbstractRoleCommand
if (!$user->isSuperAdmin()) {
$user->setSuperAdmin(true);
$userService->saveUser($user);
$output->success(sprintf('User "%s" has been promoted as a super administrator.', $username));
$output->success(\sprintf('User "%s" has been promoted as a super administrator.', $username));
} else {
$output->warning(sprintf('User "%s" does already have the super administrator role.', $username));
$output->warning(\sprintf('User "%s" does already have the super administrator role.', $username));
}
} else {
if (!$user->hasRole($role)) {
$user->addRole($role);
$userService->saveUser($user);
$output->success(sprintf('Role "%s" has been added to user "%s".', $role, $username));
$output->success(\sprintf('Role "%s" has been added to user "%s".', $role, $username));
} else {
$output->warning(sprintf('User "%s" did already have "%s" role.', $username, $role));
$output->warning(\sprintf('User "%s" did already have "%s" role.', $username, $role));
}
}
}

View File

@@ -41,7 +41,7 @@ final class RegenerateLocalesCommand extends Command
*/
private array $noRegionCode = ['ar', 'id', 'pa', 'sl'];
/**
* A list of locales that will be activated, not matter if translation files exist for them.
* A list of locales that will be activated, no matter if translation files exist for them.
*
* @var string[]
*/

View File

@@ -110,7 +110,7 @@ final class ReloadCommand extends Command
}
$io->success(
sprintf('Kimai config was reloaded')
\sprintf('Kimai config was reloaded')
);
return Command::SUCCESS;

View File

@@ -38,7 +38,7 @@ final class TimesheetStopAllCommand extends Command
if (!$output->isQuiet()) {
$io = new SymfonyStyle($input, $output);
$io->success(sprintf('Stopped %s timesheet records.', $amount));
$io->success(\sprintf('Stopped %s timesheet records.', $amount));
}
return Command::SUCCESS;

View File

@@ -28,7 +28,11 @@ use Symfony\Component\HttpClient\HttpClient;
#[AsCommand(name: 'kimai:translations')]
final class TranslationCommand extends Command
{
public function __construct(private string $projectDirectory, private string $kernelEnvironment, private LocaleService $localeService)
public function __construct(
private readonly string $projectDirectory,
private readonly string $kernelEnvironment,
private readonly LocaleService $localeService
)
{
parent::__construct();
}
@@ -70,6 +74,7 @@ final class TranslationCommand extends Command
$sources = [];
if ($input->getOption('source') !== null) {
/** @var string $tmp */
$tmp = $input->getOption('source');
foreach ($bases as $directory) {
$files = glob($directory);
@@ -95,6 +100,7 @@ final class TranslationCommand extends Command
$targets = [];
if ($input->getOption('target') !== null) {
/** @var string $tmp */
$tmp = $input->getOption('target');
foreach ($bases as $directory) {
$files = glob($directory);
@@ -402,7 +408,7 @@ final class TranslationCommand extends Command
$xmlContent = '';
foreach ($translations as $id => $values) {
$xmlContent .= sprintf(
$xmlContent .= \sprintf(
'<trans-unit id="%s" resname="%s"><source>%s</source><target>%s</target></trans-unit>',
$id,
$values['resname'],
@@ -463,7 +469,7 @@ final class TranslationCommand extends Command
if (!\array_key_exists($key, $translations)) {
throw new \Exception(
sprintf('Missing english translation for key: %s in file %s', $key, $file)
\sprintf('Missing english translation for key: %s in file %s', $key, $file)
);
}
$unit->target[0] = $translations[$key];

View File

@@ -91,7 +91,7 @@ final class UpdateCommand extends Command
if ($cacheResult !== Command::SUCCESS) {
$io->warning(
[
sprintf('Updated %s to version %s but the cache could not be rebuilt.', Constants::SOFTWARE, Constants::VERSION),
\sprintf('Updated %s to version %s but the cache could not be rebuilt.', Constants::SOFTWARE, Constants::VERSION),
'Please run the cache commands manually:',
'bin/console cache:clear --env=' . $environment . PHP_EOL .
'bin/console cache:warmup --env=' . $environment
@@ -99,7 +99,7 @@ final class UpdateCommand extends Command
);
} else {
$io->success(
sprintf('Congratulations! Successfully updated %s to version %s', Constants::SOFTWARE, Constants::VERSION)
\sprintf('Congratulations! Successfully updated %s to version %s', Constants::SOFTWARE, Constants::VERSION)
);
}

View File

@@ -46,7 +46,7 @@ final class VersionCommand extends Command
return Command::SUCCESS;
}
$io->writeln(sprintf('%s <info>%s</info> by Kevin Papst.', Constants::SOFTWARE, Constants::VERSION));
$io->writeln(\sprintf('%s <info>%s</info> by Kevin Papst.', Constants::SOFTWARE, Constants::VERSION));
return Command::SUCCESS;
}

View File

@@ -140,11 +140,11 @@ final class LocaleService
private function getConfig(string $key, string $locale): string|bool
{
if (!isset($this->languageSettings[$locale])) {
throw new \InvalidArgumentException(sprintf('Unknown locale given: %s', $locale));
throw new \InvalidArgumentException(\sprintf('Unknown locale given: %s', $locale));
}
if (!isset($this->languageSettings[$locale][$key])) {
throw new \InvalidArgumentException(sprintf('Unknown setting for locale %s: %s', $locale, $key));
throw new \InvalidArgumentException(\sprintf('Unknown setting for locale %s: %s', $locale, $key));
}
return $this->languageSettings[$locale][$key];

View File

@@ -33,6 +33,6 @@ final class ConsoleApplication extends Application
*/
public function getLongVersion(): string
{
return sprintf('%s <info>%s</info> (env: <comment>%s</>, debug: <comment>%s</>)', $this->getName(), $this->getVersion(), $this->getKernel()->getEnvironment(), $this->getKernel()->isDebug() ? 'true' : 'false');
return \sprintf('%s <info>%s</info> (env: <comment>%s</>, debug: <comment>%s</>)', $this->getName(), $this->getVersion(), $this->getKernel()->getEnvironment(), $this->getKernel()->isDebug() ? 'true' : 'false');
}
}

View File

@@ -17,11 +17,11 @@ class Constants
/**
* The current release version
*/
public const VERSION = '2.19.1';
public const VERSION = '2.20.0';
/**
* The current release: major * 10000 + minor * 100 + patch
*/
public const VERSION_ID = 21901;
public const VERSION_ID = 22000;
/**
* The software name
*/

View File

@@ -88,7 +88,7 @@ final class BookmarkController extends AbstractController
}
if (\count($enabled) > 50) {
throw new RuntimeException(sprintf('Too many columns provided, expected maximum 50, received %s.', \count($enabled)));
throw new RuntimeException(\sprintf('Too many columns provided, expected maximum 50, received %s.', \count($enabled)));
}
$user = $this->getUser();

View File

@@ -304,12 +304,12 @@ final class DoctorController extends AbstractController
)) {
foreach ($matches as $match) {
$fn = $plainText;
if (isset($match[3])) {
if (isset($match[2]) && isset($match[3])) {
$keys1 = array_keys($phpinfo);
$phpinfo[end($keys1)][$fn($match[2])] = isset($match[4]) ? [$fn($match[3]), $fn($match[4])] : $fn($match[3]);
} else {
$keys1 = array_keys($phpinfo);
$phpinfo[end($keys1)][] = $fn($match[2]);
$phpinfo[end($keys1)][] = $fn($match[2]); // @phpstan-ignore-line
}
}
}

View File

@@ -319,7 +319,7 @@ final class InvoiceController extends AbstractController
if (null === $file) {
throw $this->createNotFoundException(
sprintf('Invoice file "%s" could not be found for invoice ID "%s"', $invoice->getInvoiceFilename(), $invoice->getId())
\sprintf('Invoice file "%s" could not be found for invoice ID "%s"', $invoice->getInvoiceFilename(), $invoice->getId())
);
}

View File

@@ -243,7 +243,7 @@ final class PermissionController extends AbstractController
}
if (false === $value && $role->getName() === User::ROLE_SUPER_ADMIN && \array_key_exists($name, RolePermissionManager::SUPER_ADMIN_PERMISSIONS)) {
throw new BadRequestHttpException(sprintf('Permission "%s" cannot be deactivated for role "%s"', $name, $role->getName()));
throw new BadRequestHttpException(\sprintf('Permission "%s" cannot be deactivated for role "%s"', $name, $role->getName()));
}
try {

View File

@@ -118,7 +118,7 @@ final class QuickEntryController extends AbstractController
$startFrom = null;
if ($takeOverWeeks !== null && \intval($takeOverWeeks) > 0) {
$startFrom = clone $startWeek;
$startFrom->modify(sprintf('-%s weeks', $takeOverWeeks));
$startFrom->modify(\sprintf('-%s weeks', $takeOverWeeks));
}
$favorites = $this->favoriteRecordService->favoriteEntries($user, $amount);

View File

@@ -71,7 +71,7 @@ final class PasswordResetController extends AbstractController
if (!$user->isPasswordRequestNonExpired($this->configuration->getPasswordResetRetryLifetime())) {
if (!$user->isInternalUser()) {
throw $this->createAccessDeniedException(
sprintf('The user "%s" tried to reset the password, but it is registered as "%s" auth-type.', $user->getUserIdentifier(), $user->getAuth())
\sprintf('The user "%s" tried to reset the password, but it is registered as "%s" auth-type.', $user->getUserIdentifier(), $user->getAuth())
);
}

View File

@@ -164,7 +164,7 @@ final class SelfRegistrationController extends AbstractController
return null;
}
$key = sprintf('_security.%s.target_path', $token->getProviderKey());
$key = \sprintf('_security.%s.target_path', $token->getProviderKey());
if ($session->has($key)) {
return $session->get($key);

View File

@@ -97,7 +97,7 @@ final class TeamController extends AbstractController
$i = 1;
do {
$newName = sprintf('%s (%s)', $team->getName(), $i++);
$newName = \sprintf('%s (%s)', $team->getName(), $i++);
} while ($this->repository->count(['name' => $newName]) > 0 && $i < 10);
$newTeam->setName($newName);

View File

@@ -321,7 +321,7 @@ abstract class TimesheetAbstractController extends AbstractController
}
if ($disallowed > 0) {
$this->flashWarning(sprintf('You are missing the permission to edit %s timesheets', $disallowed));
$this->flashWarning(\sprintf('You are missing the permission to edit %s timesheets', $disallowed));
}
$dto->setEntities($timesheets);
@@ -411,7 +411,7 @@ abstract class TimesheetAbstractController extends AbstractController
$this->flashUpdateException($ex);
}
} else {
$this->flashSuccess(sprintf('No changes for %s entries detected.', \count($timesheets)));
$this->flashSuccess(\sprintf('No changes for %s entries detected.', \count($timesheets)));
return $this->redirectToRoute($this->getTimesheetRoute());
}

View File

@@ -77,7 +77,7 @@ final class AppExtension extends Extension
}
foreach ($bundleConfig as $key => $value) {
if (\array_key_exists($key, $config)) {
throw new \Exception(sprintf('Invalid bundle configuration "%s" found, skipping', $key));
throw new \Exception(\sprintf('Invalid bundle configuration "%s" found, skipping', $key));
}
$config[$key] = $value;
}

View File

@@ -31,7 +31,7 @@ class ActivityMeta implements MetaTableTypeInterface
{
if (!($entity instanceof Activity)) {
throw new \InvalidArgumentException(
sprintf('Expected instanceof Activity, received "%s"', \get_class($entity))
\sprintf('Expected instanceof Activity, received "%s"', \get_class($entity))
);
}
$this->activity = $entity;

View File

@@ -31,7 +31,7 @@ class CustomerMeta implements MetaTableTypeInterface
{
if (!($entity instanceof Customer)) {
throw new \InvalidArgumentException(
sprintf('Expected instanceof Customer, received "%s"', \get_class($entity))
\sprintf('Expected instanceof Customer, received "%s"', \get_class($entity))
);
}
$this->customer = $entity;

View File

@@ -31,7 +31,7 @@ class InvoiceMeta implements MetaTableTypeInterface
{
if (!($entity instanceof Invoice)) {
throw new \InvalidArgumentException(
sprintf('Expected instanceof Invoice, received "%s"', \get_class($entity))
\sprintf('Expected instanceof Invoice, received "%s"', \get_class($entity))
);
}
$this->invoice = $entity;

View File

@@ -31,7 +31,7 @@ class ProjectMeta implements MetaTableTypeInterface
{
if (!($entity instanceof Project)) {
throw new \InvalidArgumentException(
sprintf('Expected instanceof Project, received "%s"', \get_class($entity))
\sprintf('Expected instanceof Project, received "%s"', \get_class($entity))
);
}
$this->project = $entity;

View File

@@ -491,7 +491,7 @@ class Timesheet implements EntityWithMetaFields, ExportableItem, ModifiedAt
$allowed = [self::WORK, self::HOLIDAY, self::SICKNESS, self::PARENTAL, self::OVERTIME];
if (!\in_array($category, $allowed)) {
throw new \InvalidArgumentException(sprintf('Invalid timesheet category "%s" given, expected one of: %s', $category, implode(', ', $allowed)));
throw new \InvalidArgumentException(\sprintf('Invalid timesheet category "%s" given, expected one of: %s', $category, implode(', ', $allowed)));
}
$this->category = $category;

View File

@@ -31,7 +31,7 @@ class TimesheetMeta implements MetaTableTypeInterface
{
if (!($entity instanceof Timesheet)) {
throw new \InvalidArgumentException(
sprintf('Expected instanceof Timesheet, received "%s"', \get_class($entity))
\sprintf('Expected instanceof Timesheet, received "%s"', \get_class($entity))
);
}
$this->timesheet = $entity;

View File

@@ -17,7 +17,7 @@ final class Expose
public function __construct(public ?string $name = null, public ?string $label = null, string $type = 'string', public ?string $exp = null, public ?string $translationDomain = null)
{
if (!\in_array($type, ['string', 'datetime', 'date', 'time', 'integer', 'float', 'duration', 'boolean', 'array'])) {
throw new \InvalidArgumentException(sprintf('Unknown type "%s" on annotation "%s".', $type, self::class));
throw new \InvalidArgumentException(\sprintf('Unknown type "%s" on annotation "%s".', $type, self::class));
}
$this->type = $type;
}

View File

@@ -194,7 +194,7 @@ abstract class AbstractSpreadsheetRenderer
protected function setDurationTotal(Worksheet $sheet, int $column, int $row, string $startCoordinate, string $endCoordinate): void
{
$sheet->setCellValue(CellAddress::fromColumnAndRow($column, $row), sprintf('=SUBTOTAL(9,%s:%s)', $startCoordinate, $endCoordinate));
$sheet->setCellValue(CellAddress::fromColumnAndRow($column, $row), \sprintf('=SUBTOTAL(9,%s:%s)', $startCoordinate, $endCoordinate));
$style = $sheet->getStyle(CellAddress::fromColumnAndRow($column, $row));
$style->getNumberFormat()->setFormatCode($this->durationFormat);
}
@@ -204,19 +204,19 @@ abstract class AbstractSpreadsheetRenderer
if (null === $duration) {
$duration = 0;
}
$sheet->setCellValue(CellAddress::fromColumnAndRow($column, $row), sprintf('=%s/%s', $duration, $this->durationBase));
$sheet->setCellValue(CellAddress::fromColumnAndRow($column, $row), \sprintf('=%s/%s', $duration, $this->durationBase));
$sheet->getStyle(CellAddress::fromColumnAndRow($column, $row))->getNumberFormat()->setFormatCode($this->durationFormat);
}
protected function setRateTotal(Worksheet $sheet, int $column, int $row, string $startCoordinate, string $endCoordinate): void
{
$sheet->setCellValue(CellAddress::fromColumnAndRow($column, $row), sprintf('=SUBTOTAL(9,%s:%s)', $startCoordinate, $endCoordinate));
$sheet->setCellValue(CellAddress::fromColumnAndRow($column, $row), \sprintf('=SUBTOTAL(9,%s:%s)', $startCoordinate, $endCoordinate));
}
protected function setRateStyle(Worksheet $sheet, int $column, int $row, ?string $currency): void
{
$sheet->getStyle(CellAddress::fromColumnAndRow($column, $row))->getNumberFormat()->setFormatCode(
sprintf($this->rateFormat, $currency ?? '')
\sprintf($this->rateFormat, $currency ?? '')
);
}
@@ -710,7 +710,7 @@ abstract class AbstractSpreadsheetRenderer
}
if (!\array_key_exists('render', $settings) || !\is_callable($settings['render'])) {
throw new \RuntimeException(sprintf('Missing or invalid renderer for export column %s', $label));
throw new \RuntimeException(\sprintf('Missing or invalid renderer for export column %s', $label));
}
$amount = $settings['render']($sheet, $entryHeaderRow, $entryHeaderColumn, $exportItem);

View File

@@ -57,7 +57,7 @@ class CsvRenderer extends AbstractSpreadsheetRenderer
protected function setDuration(Worksheet $sheet, int $column, int $row, ?int $duration): void
{
$sheet->setCellValue(CellAddress::fromColumnAndRow($column, $row), sprintf('=%s', $duration ?? 0));
$sheet->setCellValue(CellAddress::fromColumnAndRow($column, $row), \sprintf('=%s', $duration ?? 0));
}
protected function setRate(Worksheet $sheet, int $column, int $row, ?float $rate, ?string $currency): void

View File

@@ -161,7 +161,7 @@ final class ServiceExport
$items = array_merge($items, $repository->getExportItemsForQuery($query));
if ($max !== null && \count($items) > $max) {
throw new TooManyItemsExportException(
sprintf('Limit reached! Expected max. %s items but got %s', $max, \count($items))
\sprintf('Limit reached! Expected max. %s items but got %s', $max, \count($items))
);
}
}

View File

@@ -26,7 +26,7 @@ final class DurationFormatter implements CellFormatterInterface
throw new \InvalidArgumentException('Unsupported value given, only int is supported');
}
$sheet->setCellValue(CellAddress::fromColumnAndRow($column, $row), sprintf('=%s/86400', $value));
$sheet->setCellValue(CellAddress::fromColumnAndRow($column, $row), \sprintf('=%s/86400', $value));
$sheet->getStyle(CellAddress::fromColumnAndRow($column, $row))->getNumberFormat()->setFormatCode(self::DURATION_FORMAT);
}
}

View File

@@ -56,13 +56,13 @@ final class AnnotationExtractor implements ExtractorInterface
foreach ($definitions as $definition) {
$arguments = $definition->getArguments();
if (!\array_key_exists('name', $arguments) || $arguments['name'] === null) {
throw new ExtractorException(sprintf('@Expose needs the "name" attribute on class level hierarchy, check %s::class', $value));
throw new ExtractorException(\sprintf('@Expose needs the "name" attribute on class level hierarchy, check %s::class', $value));
}
if (!\array_key_exists('exp', $arguments) || $arguments['exp'] === null) {
throw new ExtractorException(sprintf('@Expose needs the "exp" attribute on class level hierarchy, check %s::class', $value));
throw new ExtractorException(\sprintf('@Expose needs the "exp" attribute on class level hierarchy, check %s::class', $value));
}
if (!\array_key_exists('label', $arguments) || $arguments['label'] === null) {
throw new ExtractorException(sprintf('@Expose needs the "label" attribute on class level hierarchy, check %s::class', $value));
throw new ExtractorException(\sprintf('@Expose needs the "label" attribute on class level hierarchy, check %s::class', $value));
}
$parsed = $this->expressionLanguage->parse($arguments['exp'], ['object']);
@@ -87,10 +87,10 @@ final class AnnotationExtractor implements ExtractorInterface
foreach ($definitions as $definition) {
$arguments = $definition->getArguments();
if (\array_key_exists('exp', $arguments) && $arguments['exp'] !== null) {
throw new ExtractorException(sprintf('@Expose only supports the "exp" attribute on class level hierarchy, check %s::$%s', $value, $property->getName()));
throw new ExtractorException(\sprintf('@Expose only supports the "exp" attribute on class level hierarchy, check %s::$%s', $value, $property->getName()));
}
if (!\array_key_exists('label', $arguments) || $arguments['label'] === null) {
throw new ExtractorException(sprintf('@Expose needs the "label" attribute on property level hierarchy, check %s::$%s', $value, $property->getName()));
throw new ExtractorException(\sprintf('@Expose needs the "label" attribute on property level hierarchy, check %s::$%s', $value, $property->getName()));
}
$name = $property->getName();
@@ -120,15 +120,15 @@ final class AnnotationExtractor implements ExtractorInterface
$definitions = $method->getAttributes(Expose::class);
foreach ($definitions as $definition) {
if (\count($method->getParameters()) > 0) {
throw new ExtractorException(sprintf('@Expose does not support method %s::%s(...) as it has required parameters.', $value, $method->getName()));
throw new ExtractorException(\sprintf('@Expose does not support method %s::%s(...) as it has required parameters.', $value, $method->getName()));
}
$arguments = $definition->getArguments();
if (\array_key_exists('exp', $arguments) && $arguments['exp'] !== null) {
throw new ExtractorException(sprintf('@Expose only supports the "exp" attribute on method level hierarchy, check %s::%s()', $value, $method->getName()));
throw new ExtractorException(\sprintf('@Expose only supports the "exp" attribute on method level hierarchy, check %s::%s()', $value, $method->getName()));
}
if (!\array_key_exists('label', $arguments) || $arguments['label'] === null) {
throw new ExtractorException(sprintf('@Expose needs the "label" attribute on method level hierarchy, check %s::%s()', $value, $method->getName()));
throw new ExtractorException(\sprintf('@Expose needs the "label" attribute on method level hierarchy, check %s::%s()', $value, $method->getName()));
}
$name = $method->getName();

View File

@@ -30,7 +30,7 @@ final class ColorPickerType extends AbstractType implements DataTransformerInter
$resolver->setDefaults([
'documentation' => [
'type' => 'string',
'description' => sprintf('The hexadecimal color code (default: %s)', self::DEFAULT_COLOR),
'description' => \sprintf('The hexadecimal color code (default: %s)', self::DEFAULT_COLOR),
],
'label' => 'color',
'empty_data' => null,

View File

@@ -49,7 +49,8 @@ final class DateRangeType extends AbstractType
'max_day' => null,
'locale' => \Locale::getDefault(),
]);
$resolver->addAllowedTypes('timezone', ['string']);
$resolver->setAllowedTypes('separator', 'string');
$resolver->addAllowedTypes('timezone', 'string');
$resolver->addAllowedTypes('min_day', ['null', 'string', \DateTimeInterface::class]);
$resolver->addAllowedTypes('max_day', ['null', 'string', \DateTimeInterface::class]);
@@ -59,6 +60,7 @@ final class DateRangeType extends AbstractType
return $converter->convert($format);
});
$resolver->setAllowedTypes('format', ['string']);
$resolver->setDefault('attr', function (Options $options): array {
$format = $this->localeService->getDateFormat($options['locale']);
@@ -115,7 +117,10 @@ final class DateRangeType extends AbstractType
}
}
public function buildForm(FormBuilderInterface $builder, array $options): void
/**
* @param array{'format': non-empty-string, 'separator': non-empty-string, 'allow_empty': true, 'timezone': non-empty-string} $options
*/
public function buildForm(FormBuilderInterface $builder, array $options): void // @phpstan-ignore-line
{
$formatDate = $options['format'];
$separator = $options['separator'];

View File

@@ -34,6 +34,7 @@ final class DurationType extends AbstractType
'max_hours' => 24,
'icon' => 'clock',
]);
$resolver->setAllowedTypes('max_hours', 'int');
}
public function buildView(FormView $view, FormInterface $form, array $options): void
@@ -54,7 +55,7 @@ final class DurationType extends AbstractType
}
// we track times for humans and no entry should ever be that long
if ($maxHours > $options['max_hours']) {
if (\is_int($options['max_hours']) && $maxHours > $options['max_hours']) {
$maxHours = $options['max_hours'];
}

View File

@@ -36,7 +36,7 @@ final class UserLocaleType extends AbstractType
$resolver->setDefaults([
'label' => 'locale',
'help_html' => true,
'help' => sprintf('<a href="%1$s" target="help_locales">%2$s</a>', $route, $moreLink)
'help' => \sprintf('<a href="%1$s" target="help_locales">%2$s</a>', $route, $moreLink)
]);
}

View File

@@ -212,11 +212,11 @@ final class ServiceInvoice
}
if (mb_strlen($filename) >= 150) {
throw new \Exception(sprintf('Invoice filename "%s" is too long, max. 150 characters allowed', $filename));
throw new \Exception(\sprintf('Invoice filename "%s" is too long, max. 150 characters allowed', $filename));
}
if (is_file($invoiceDirectory . $filename)) {
throw new \Exception(sprintf('Invoice "%s" already exists', $filename));
throw new \Exception(\sprintf('Invoice "%s" already exists', $filename));
}
if ($response instanceof BinaryFileResponse) {
@@ -303,7 +303,7 @@ final class ServiceInvoice
}
throw new \Exception(
sprintf('Cannot render invoice: %s (%s)', $model->getTemplate()->getRenderer(), $document->getName())
\sprintf('Cannot render invoice: %s (%s)', $model->getTemplate()->getRenderer(), $document->getName())
);
}
@@ -354,7 +354,7 @@ final class ServiceInvoice
}
throw new \Exception(
sprintf('Cannot render invoice: %s (%s)', $model->getTemplate()->getRenderer(), $document->getName())
\sprintf('Cannot render invoice: %s (%s)', $model->getTemplate()->getRenderer(), $document->getName())
);
}

View File

@@ -106,13 +106,13 @@ class Kernel extends BaseKernel
$plugin = new $pluginClass();
if (!$plugin instanceof PluginInterface) {
throw new \Exception(sprintf('Bundle "%s" does not implement %s, which is not supported since 2.0.', $bundleName, PluginInterface::class));
throw new \Exception(\sprintf('Bundle "%s" does not implement %s, which is not supported since 2.0.', $bundleName, PluginInterface::class));
}
$meta = new PluginMetadata($fullPath);
if ($meta->getKimaiVersion() > Constants::VERSION_ID) {
throw new \Exception(sprintf('Bundle "%s" requires minimum Kimai version %s, but yours is lower: %s (%s). Please update Kimai or use a lower Plugin version.', $bundleName, $meta->getKimaiVersion(), Constants::VERSION, Constants::VERSION_ID));
throw new \Exception(\sprintf('Bundle "%s" requires minimum Kimai version %s, but yours is lower: %s (%s). Please update Kimai or use a lower Plugin version.', $bundleName, $meta->getKimaiVersion(), Constants::VERSION, Constants::VERSION_ID));
}
$plugins[] = $plugin;

View File

@@ -77,7 +77,7 @@ final class LdapAuthenticator implements AuthenticationEntryPointInterface, Inte
public function start(Request $request, AuthenticationException $authException = null): Response
{
if (!$this->authenticator instanceof AuthenticationEntryPointInterface) {
throw new NotAnEntryPointException(sprintf('Decorated authenticator "%s" does not implement interface "%s".', get_debug_type($this->authenticator), AuthenticationEntryPointInterface::class));
throw new NotAnEntryPointException(\sprintf('Decorated authenticator "%s" does not implement interface "%s".', get_debug_type($this->authenticator), AuthenticationEntryPointInterface::class));
}
return $this->authenticator->start($request, $authException);

View File

@@ -41,7 +41,7 @@ final class LdapCredentialsSubscriber implements EventSubscriberInterface
}
if (!$passport instanceof Passport || !$passport->hasBadge(PasswordCredentials::class)) {
throw new \LogicException(sprintf('LDAP authentication requires a passport containing a user and password credentials, authenticator "%s" does not fulfill these requirements.', \get_class($event->getAuthenticator())));
throw new \LogicException(\sprintf('LDAP authentication requires a passport containing a user and password credentials, authenticator "%s" does not fulfill these requirements.', \get_class($event->getAuthenticator())));
}
/** @var PasswordCredentials $passwordCredentials */

View File

@@ -60,10 +60,10 @@ class LdapManager
$filters[] = $params['filter'];
foreach ($criteria as $key => $value) {
$value = ldap_escape($value, '', LDAP_ESCAPE_FILTER);
$filters[] = sprintf('(%s=%s)', $key, $value);
$filters[] = \sprintf('(%s=%s)', $key, $value);
}
return sprintf('(%s%s)', $condition, implode($filters));
return \sprintf('(%s%s)', $condition, implode($filters));
}
public function bind(string $dn, string $password): bool
@@ -84,7 +84,7 @@ class LdapManager
// always look up the users current DN first, as the current user might be upgraded from local to LDAP
$userFresh = $this->findUserByUsername($user->getUserIdentifier());
if (null === $userFresh || null === ($baseDn = $userFresh->getPreferenceValue('ldap_dn'))) {
throw new LdapDriverException(sprintf('Failed fetching user DN for %s', $user->getUserIdentifier()));
throw new LdapDriverException(\sprintf('Failed fetching user DN for %s', $user->getUserIdentifier()));
}
$user->setPreferenceValue('ldap_dn', $baseDn);
@@ -128,7 +128,7 @@ class LdapManager
return $this->driver->search(
$roleParameter['baseDn'],
sprintf('(&%s(%s=%s))', $filter, $roleParameter['userDnAttribute'], ldap_escape($dn, '', LDAP_ESCAPE_FILTER)),
\sprintf('(&%s(%s=%s))', $filter, $roleParameter['userDnAttribute'], ldap_escape($dn, '', LDAP_ESCAPE_FILTER)),
[$roleParameter['nameAttribute']]
);
}
@@ -200,7 +200,7 @@ class LdapManager
}
if (!$mapped) {
$roleName = sprintf('ROLE_%s', self::slugify($roleName));
$roleName = \sprintf('ROLE_%s', self::slugify($roleName));
}
if (!\in_array($roleName, $allowedRoles, true)) {

View File

@@ -35,7 +35,7 @@ final class LdapUserProvider implements UserProviderInterface
'username' => $identifier,
'result' => 'not found',
]);
$ex = new UserNotFoundException(sprintf('User "%s" not found', $identifier));
$ex = new UserNotFoundException(\sprintf('User "%s" not found', $identifier));
$ex->setUserIdentifier($identifier);
throw $ex;
@@ -53,17 +53,17 @@ final class LdapUserProvider implements UserProviderInterface
public function refreshUser(UserInterface $user): UserInterface
{
if (!($user instanceof User)) {
throw new UnsupportedUserException(sprintf('Instances of "%s" are not supported.', \get_class($user)));
throw new UnsupportedUserException(\sprintf('Instances of "%s" are not supported.', \get_class($user)));
}
if (!$user->isLdapUser()) {
throw new UnsupportedUserException(sprintf('Account "%s" is not a registered LDAP user.', $user->getUserIdentifier()));
throw new UnsupportedUserException(\sprintf('Account "%s" is not a registered LDAP user.', $user->getUserIdentifier()));
}
try {
$this->ldapManager->updateUser($user);
} catch (LdapDriverException $ex) {
throw new UnsupportedUserException(sprintf('Failed to refresh user "%s", probably DN is expired.', $user->getUserIdentifier()));
throw new UnsupportedUserException(\sprintf('Failed to refresh user "%s", probably DN is expired.', $user->getUserIdentifier()));
}
return $user;

View File

@@ -25,7 +25,7 @@ final class Month extends Timesheet
$monthNumber = (int) $month;
if ($monthNumber < 1 || $monthNumber > 12) {
throw new InvalidArgumentException(
sprintf('Invalid month given. Expected 1-12, received "%s".', $monthNumber)
\sprintf('Invalid month given. Expected 1-12, received "%s".', $monthNumber)
);
}
$this->month = str_pad($month, 2, '0', STR_PAD_LEFT);

View File

@@ -25,36 +25,36 @@ class PluginMetadata
public function __construct(string $path)
{
if (!is_dir($path) || !is_readable($path)) {
throw new \Exception(sprintf('Bundle directory "%s" cannot be accessed.', $path));
throw new \Exception(\sprintf('Bundle directory "%s" cannot be accessed.', $path));
}
$pluginName = basename($path);
$composer = $path . '/composer.json';
if (!file_exists($composer) || !is_readable($composer)) {
throw new \Exception(sprintf('Bundle "%s" does not ship composer.json, which is required since 2.0.', $pluginName));
throw new \Exception(\sprintf('Bundle "%s" does not ship composer.json, which is required since 2.0.', $pluginName));
}
$json = json_decode(file_get_contents($composer), true);
if (!\array_key_exists('extra', $json)) {
throw new \Exception(sprintf('Bundle "%s" does not define an "extra" node in composer.json, which is required since 2.0.', $pluginName));
throw new \Exception(\sprintf('Bundle "%s" does not define an "extra" node in composer.json, which is required since 2.0.', $pluginName));
}
if (!\array_key_exists('kimai', $json['extra'])) {
throw new \Exception(sprintf('Bundle "%s" does not define the "extra.kimai" node in composer.json, which is required since 2.0.', $pluginName));
throw new \Exception(\sprintf('Bundle "%s" does not define the "extra.kimai" node in composer.json, which is required since 2.0.', $pluginName));
}
if (!\array_key_exists('require', $json['extra']['kimai'])) {
throw new \Exception(sprintf('Bundle "%s" does not define the minimum Kimai version in "extra.kimai.required" in composer.json, which is required since 2.0.', $pluginName));
throw new \Exception(\sprintf('Bundle "%s" does not define the minimum Kimai version in "extra.kimai.required" in composer.json, which is required since 2.0.', $pluginName));
}
if (!\array_key_exists('name', $json['extra']['kimai'])) {
throw new \Exception(sprintf('Bundle "%s" does not define its name in "extra.kimai.name" in composer.json, which is required since 2.0.', $pluginName));
throw new \Exception(\sprintf('Bundle "%s" does not define its name in "extra.kimai.name" in composer.json, which is required since 2.0.', $pluginName));
}
if (!\is_int($json['extra']['kimai']['require'])) {
throw new \Exception(sprintf('Bundle "%s" defines an invalid Kimai minimum version in extra.kimai.require. Please provide an integer as in Constants::VERSION_ID.', $pluginName));
throw new \Exception(\sprintf('Bundle "%s" defines an invalid Kimai minimum version in extra.kimai.require. Please provide an integer as in Constants::VERSION_ID.', $pluginName));
}
$this->description = $json['description'] ?? '';

View File

@@ -76,7 +76,7 @@ trait RepositorySearchTrait
$and->add($qb->expr()->isNotNull($alias . '.value'));
} elseif ($metaValue === '~') {
$and->add(
sprintf('NOT EXISTS(SELECT metaNotExists FROM %s metaNotExists WHERE metaNotExists.%s = %s.id)', $this->getMetaFieldClass(), $this->getMetaFieldName(), $rootAlias)
\sprintf('NOT EXISTS(SELECT metaNotExists FROM %s metaNotExists WHERE metaNotExists.%s = %s.id)', $this->getMetaFieldClass(), $this->getMetaFieldName(), $rootAlias)
);
} elseif ($metaValue === '' || $metaValue === null) {
$qb->leftJoin($rootAlias . '.meta', $alias);
@@ -86,7 +86,7 @@ trait RepositorySearchTrait
$qb->expr()->eq($alias . '.name', ':' . $paramName),
$qb->expr()->isNull($alias . '.value')
),
sprintf('NOT EXISTS(SELECT metaNotExists FROM %s metaNotExists WHERE metaNotExists.%s = %s.id)', $this->getMetaFieldClass(), $this->getMetaFieldName(), $rootAlias)
\sprintf('NOT EXISTS(SELECT metaNotExists FROM %s metaNotExists WHERE metaNotExists.%s = %s.id)', $this->getMetaFieldClass(), $this->getMetaFieldName(), $rootAlias)
)
);
$qb->setParameter($paramName, $metaName);

View File

@@ -98,7 +98,7 @@ class SamlAuthenticator extends AbstractAuthenticator
if (isset($this->options['username_attribute'])) {
if (!\array_key_exists($this->options['username_attribute'], $attributes)) {
throw new \Exception(sprintf("Attribute '%s' not found in SAML data", $this->options['username_attribute']));
throw new \Exception(\sprintf("Attribute '%s' not found in SAML data", $this->options['username_attribute']));
}
$username = $attributes[$this->options['username_attribute']][0];

View File

@@ -32,7 +32,7 @@ final class SamlLoginAttributes
public function getAttribute(string $name): mixed
{
if (!\array_key_exists($name, $this->attributes)) {
throw new \InvalidArgumentException(sprintf('This SAML login has no "%s" attribute.', $name));
throw new \InvalidArgumentException(\sprintf('This SAML login has no "%s" attribute.', $name));
}
return $this->attributes[$name];

View File

@@ -54,7 +54,7 @@ final class SamlProvider
} catch (\Exception $ex) {
$this->logger->error($ex->getMessage());
throw new AuthenticationException(
sprintf('Failed creating or hydrating user "%s": %s', $token->getUserIdentifier(), $ex->getMessage())
\sprintf('Failed creating or hydrating user "%s": %s', $token->getUserIdentifier(), $ex->getMessage())
);
}

View File

@@ -173,7 +173,7 @@ final class LocaleFormatExtensions extends AbstractExtension implements LocaleAw
}
$months = [];
for ($i = 1; $i < 13; $i++) {
$months[] = $this->getFormatter()->monthName(new DateTime(sprintf('%s-%s-10', $year, ($i < 10 ? '0' . $i : (string) $i))), $withYear);
$months[] = $this->getFormatter()->monthName(new DateTime(\sprintf('%s-%s-10', $year, ($i < 10 ? '0' . $i : (string) $i))), $withYear);
}
return $months;

View File

@@ -37,7 +37,7 @@ final class WidgetExtension implements RuntimeExtensionInterface
if (\is_string($widget)) {
if (!$this->service->hasWidget($widget)) {
throw new \InvalidArgumentException(sprintf('Unknown widget "%s" requested', $widget));
throw new \InvalidArgumentException(\sprintf('Unknown widget "%s" requested', $widget));
}
$widget = $this->service->getWidget($widget);

View File

@@ -51,19 +51,19 @@ final class ForbiddenPolicy implements SecurityPolicyInterface
{
foreach ($tags as $tag) {
if (\in_array($tag, $this->forbiddenTags)) {
throw new SecurityNotAllowedTagError(sprintf('Tag "%s" is not allowed.', $tag), $tag);
throw new SecurityNotAllowedTagError(\sprintf('Tag "%s" is not allowed.', $tag), $tag);
}
}
foreach ($filters as $filter) {
if (\in_array($filter, $this->forbiddenFilters)) {
throw new SecurityNotAllowedFilterError(sprintf('Filter "%s" is not allowed.', $filter), $filter);
throw new SecurityNotAllowedFilterError(\sprintf('Filter "%s" is not allowed.', $filter), $filter);
}
}
foreach ($functions as $function) {
if (\in_array($function, $this->forbiddenFunctions)) {
throw new SecurityNotAllowedFunctionError(sprintf('Function "%s" is not allowed.', $function), $function);
throw new SecurityNotAllowedFunctionError(\sprintf('Function "%s" is not allowed.', $function), $function);
}
}
}
@@ -86,7 +86,7 @@ final class ForbiddenPolicy implements SecurityPolicyInterface
if ($forbidden) {
$class = \get_class($obj);
throw new SecurityNotAllowedMethodError(sprintf('Calling "%s" method on a "%s" object is not allowed.', $method, $class), $class, $method);
throw new SecurityNotAllowedMethodError(\sprintf('Calling "%s" method on a "%s" object is not allowed.', $method, $class), $class, $method);
}
}
@@ -103,7 +103,7 @@ final class ForbiddenPolicy implements SecurityPolicyInterface
if ($forbidden) {
$class = \get_class($obj);
throw new SecurityNotAllowedPropertyError(sprintf('Calling "%s" property on a "%s" object is not allowed.', $property, $class), $class, $property);
throw new SecurityNotAllowedPropertyError(\sprintf('Calling "%s" property on a "%s" object is not allowed.', $property, $class), $class, $property);
}
}
}

View File

@@ -136,7 +136,7 @@ class UserService
$user = $this->findUserByName($username);
if ($user === null) {
throw new \InvalidArgumentException(sprintf('User identified by "%s" username does not exist.', $username));
throw new \InvalidArgumentException(\sprintf('User identified by "%s" username does not exist.', $username));
}
return $user;

View File

@@ -96,7 +96,7 @@ final class Color
public function getRandomColor(): string
{
return sprintf('#%06x', rand(0, 16777215));
return \sprintf('#%06x', rand(0, 16777215));
}
public function getRandomFromPalette(string $input): string

View File

@@ -85,7 +85,7 @@ final class Duration
self::FORMAT_COLON => $this->parseColonFormat($duration),
self::FORMAT_NATURAL => $this->parseNaturalFormat($duration),
self::FORMAT_DECIMAL => $this->parseDecimalFormat($duration),
default => throw new \InvalidArgumentException(sprintf('Unsupported duration format "%s"', $mode)),
default => throw new \InvalidArgumentException(\sprintf('Unsupported duration format "%s"', $mode)),
};
}
@@ -116,7 +116,7 @@ final class Duration
$parts = explode(':', $duration);
if (\count($parts) < 2 || \count($parts) > 3) {
throw new \InvalidArgumentException(
sprintf('Invalid colon format given in "%s"', $duration)
\sprintf('Invalid colon format given in "%s"', $duration)
);
}
@@ -124,13 +124,13 @@ final class Duration
foreach ($parts as $part) {
if (\strlen($part) === 0) {
throw new \InvalidArgumentException(
sprintf('Colon format cannot parse "%s"', $duration)
\sprintf('Colon format cannot parse "%s"', $duration)
);
}
// the entire time could be negative
if ($i++ > 0 && ((int) $part) < 0) {
throw new \InvalidArgumentException(
sprintf('Negative input is not allowed in "%s"', $duration)
\sprintf('Negative input is not allowed in "%s"', $duration)
);
}
}

View File

@@ -40,11 +40,11 @@ final class FileHelper
$this->makeDir($directory);
if (!is_dir($directory)) {
throw new \Exception(sprintf('Directory "%s" does not exist', $directory));
throw new \Exception(\sprintf('Directory "%s" does not exist', $directory));
}
if (!is_writable($directory)) {
throw new \Exception(sprintf('Directory "%s" is not writable', $directory));
throw new \Exception(\sprintf('Directory "%s" is not writable', $directory));
}
return $directory;

View File

@@ -39,9 +39,9 @@ final class PaginationTemplate extends TwitterBootstrap5Template
protected function linkLi(string $class, string $href, $text, ?string $rel = null): string
{
$liClass = implode(' ', array_filter(['page-item', $class]));
$rel = $rel ? sprintf(' rel="%s"', $rel) : '';
$rel = $rel ? \sprintf(' rel="%s"', $rel) : '';
return sprintf('<li class="%s"><a class="page-link pagination-link" href="%s"%s>%s</a></li>', $liClass, $href, $rel, $text);
return \sprintf('<li class="%s"><a class="page-link pagination-link" href="%s"%s>%s</a></li>', $liClass, $href, $rel, $text);
}
/**
@@ -53,7 +53,7 @@ final class PaginationTemplate extends TwitterBootstrap5Template
{
$liClass = implode(' ', array_filter(['page-item', $class]));
return sprintf('<li class="%s"><span class="page-link pagination-link">%s</span></li>', $liClass, $text);
return \sprintf('<li class="%s"><span class="page-link pagination-link">%s</span></li>', $liClass, $text);
}
public function current(int $page): string

View File

@@ -130,6 +130,6 @@ abstract class AbstractWidget implements WidgetInterface
{
$name = (new \ReflectionClass($this))->getShortName();
return sprintf('widget/widget-%s.html.twig', strtolower($name));
return \sprintf('widget/widget-%s.html.twig', strtolower($name));
}
}

View File

@@ -128,8 +128,8 @@ final class PaginatedWorkingTimeChart extends AbstractWidget
$monthBegin = (clone $weekBegin)->setDate((int) $weekBegin->format('Y'), (int) $weekBegin->format('n'), 1)->setTime(0, 0, 0);
$monthEnd = (clone $weekBegin)->setDate((int) $weekBegin->format('Y'), (int) $weekBegin->format('n'), (int) $weekBegin->format('t'))->setTime(23, 59, 59);
$yearBegin = $dateTimeFactory->createDateTime(sprintf('01 january %s 00:00:00', $year));
$yearEnd = $dateTimeFactory->createDateTime(sprintf('31 december %s 23:59:59', $year));
$yearBegin = $dateTimeFactory->createDateTime(\sprintf('01 january %s 00:00:00', $year));
$yearEnd = $dateTimeFactory->createDateTime(\sprintf('31 december %s 23:59:59', $year));
$yearData = $this->repository->getDurationForTimeRange($yearBegin, $yearEnd, $user);
$financialYearData = null;

View File

@@ -41,7 +41,7 @@ class WidgetService
public function getWidget(string $id): WidgetInterface
{
if (!$this->hasWidget($id)) {
throw new \InvalidArgumentException(sprintf('Cannot find widget: %s', $id));
throw new \InvalidArgumentException(\sprintf('Cannot find widget: %s', $id));
}
return $this->widgets[$id];

View File

@@ -39,7 +39,7 @@ abstract class APIControllerBaseTest extends ControllerBaseTest
User::ROLE_ADMIN => self::createClient([], $this->getAuthHeader(UserFixtures::USERNAME_ADMIN, UserFixtures::DEFAULT_API_TOKEN . '_admin')),
User::ROLE_TEAMLEAD => self::createClient([], $this->getAuthHeader(UserFixtures::USERNAME_TEAMLEAD, UserFixtures::DEFAULT_API_TOKEN . '_teamlead')),
User::ROLE_USER => self::createClient([], $this->getAuthHeader(UserFixtures::USERNAME_USER, UserFixtures::DEFAULT_API_TOKEN . '_user')),
default => throw new \Exception(sprintf('Unknown role "%s"', $role)),
default => throw new \Exception(\sprintf('Unknown role "%s"', $role)),
};
}
@@ -74,13 +74,13 @@ abstract class APIControllerBaseTest extends ControllerBaseTest
self::assertEquals(
$data,
json_decode($response->getContent(), true),
sprintf('The secure URL %s is not protected.', $url)
\sprintf('The secure URL %s is not protected.', $url)
);
self::assertEquals(
Response::HTTP_UNAUTHORIZED,
$response->getStatusCode(),
sprintf('The secure URL %s has the wrong status code %s.', $url, $response->getStatusCode())
\sprintf('The secure URL %s has the wrong status code %s.', $url, $response->getStatusCode())
);
}
@@ -91,7 +91,7 @@ abstract class APIControllerBaseTest extends ControllerBaseTest
self::assertFalse(
$client->getResponse()->isSuccessful(),
sprintf('The secure URL %s is not protected for role %s', $url, $role)
\sprintf('The secure URL %s is not protected for role %s', $url, $role)
);
$this->assertApiException($client->getResponse(), [
@@ -248,7 +248,7 @@ abstract class APIControllerBaseTest extends ControllerBaseTest
while (stripos($fieldName, '.') !== false) {
$parts = explode('.', $fieldName);
$tmp = array_shift($parts);
self::assertArrayHasKey($tmp, $data, sprintf('Could not find field "%s" in result', $tmp));
self::assertArrayHasKey($tmp, $data, \sprintf('Could not find field "%s" in result', $tmp));
$data = $data[$tmp];
if (\count($data) === 1 && \array_key_exists('children', $data)) {
$data = $data['children'];
@@ -256,8 +256,8 @@ abstract class APIControllerBaseTest extends ControllerBaseTest
$fieldName = implode('.', $parts);
}
self::assertArrayHasKey($fieldName, $data, sprintf('Could not find validation error for field "%s" in list: %s', $fieldName, implode(', ', $failedFields)));
self::assertArrayHasKey('errors', $data[$fieldName], sprintf('Field %s has no validation problem', $fieldName));
self::assertArrayHasKey($fieldName, $data, \sprintf('Could not find validation error for field "%s" in list: %s', $fieldName, implode(', ', $failedFields)));
self::assertArrayHasKey('errors', $data[$fieldName], \sprintf('Field %s has no validation problem', $fieldName));
foreach ($messages as $i => $message) {
self::assertEquals($message, $data[$fieldName]['errors'][$i]);
}
@@ -648,7 +648,7 @@ abstract class APIControllerBaseTest extends ControllerBaseTest
];
default:
throw new \Exception(sprintf('Unknown API response type: %s', $type));
throw new \Exception(\sprintf('Unknown API response type: %s', $type));
}
}
@@ -668,12 +668,12 @@ abstract class APIControllerBaseTest extends ControllerBaseTest
sort($actual);
sort($expectedKeys);
self::assertEquals($expectedKeys, $actual, sprintf('Structure for API response type "%s" does not match', $type));
self::assertEquals($expectedKeys, $actual, \sprintf('Structure for API response type "%s" does not match', $type));
self::assertEquals(
\count($actual),
\count($expectedKeys),
sprintf('Mismatch between expected and result keys for API response type "%s". Expected %s keys but found %s.', $type, \count($expected), \count($actual))
\sprintf('Mismatch between expected and result keys for API response type "%s". Expected %s keys but found %s.', $type, \count($expected), \count($actual))
);
foreach ($expected as $key => $value) {
@@ -706,13 +706,13 @@ abstract class APIControllerBaseTest extends ControllerBaseTest
$value['type'] = substr($value['type'], 1);
}
self::assertIsArray($result[$key], sprintf('Key "%s" in type "%s" is not an array', $key, $type));
self::assertIsArray($result[$key], \sprintf('Key "%s" in type "%s" is not an array', $key, $type));
self::assertApiResponseTypeStructure($value['type'], $result[$key]);
break;
default:
throw new \Exception(sprintf('Invalid result type "%s" for subresource given', $value['result']));
throw new \Exception(\sprintf('Invalid result type "%s" for subresource given', $value['result']));
}
continue;
@@ -727,18 +727,18 @@ abstract class APIControllerBaseTest extends ControllerBaseTest
if (strtolower($value) === 'datetime') {
$date = \DateTime::createFromFormat('Y-m-d\TH:i:sO', $result[$key]);
self::assertInstanceOf(\DateTime::class, $date, sprintf('Field "%s" was expected to be a Date with the format "Y-m-dTH:i:sO", but found: %s', $key, $result[$key]));
self::assertInstanceOf(\DateTime::class, $date, \sprintf('Field "%s" was expected to be a Date with the format "Y-m-dTH:i:sO", but found: %s', $key, $result[$key]));
$value = 'string';
} elseif (strtolower($value) === 'date') {
$date = \DateTime::createFromFormat('Y-m-d', $result[$key]);
self::assertInstanceOf(\DateTime::class, $date, sprintf('Field "%s" was expected to be a Date with the format "Y-m-d", but found: %s', $key, $result[$key]));
self::assertInstanceOf(\DateTime::class, $date, \sprintf('Field "%s" was expected to be a Date with the format "Y-m-d", but found: %s', $key, $result[$key]));
$value = 'string';
}
static::assertThat(
$result[$key],
new IsType($value),
sprintf('Found type mismatch in structure for API response type %s. Expected type "%s" for key "%s".', $type, $value, $key)
\sprintf('Found type mismatch in structure for API response type %s. Expected type "%s" for key "%s".', $type, $value, $key)
);
}
}

View File

@@ -55,7 +55,7 @@ class ActionsControllerTest extends APIControllerBaseTest
];
foreach ($views as $view => $entries) {
$this->assertAccessIsGranted($client, sprintf('/api/actions/timesheet/%s/%s/en', $items[0]->getId(), $view));
$this->assertAccessIsGranted($client, \sprintf('/api/actions/timesheet/%s/%s/en', $items[0]->getId(), $view));
$result = json_decode($client->getResponse()->getContent(), true);
$this->assertIsArray($result);
@@ -65,7 +65,7 @@ class ActionsControllerTest extends APIControllerBaseTest
$i = 0;
foreach ($entries as $id) {
self::assertEquals($id, $result[$i]['id'], sprintf('Failed action "%s" with name "%s" in view "%s"', $i, $id, $view));
self::assertEquals($id, $result[$i]['id'], \sprintf('Failed action "%s" with name "%s" in view "%s"', $i, $id, $view));
$i++;
}
}
@@ -105,7 +105,7 @@ class ActionsControllerTest extends APIControllerBaseTest
];
foreach ($views as $view => $entries) {
$this->assertAccessIsGranted($client, sprintf('/api/actions/activity/%s/%s/en', $activities[0]->getId(), $view));
$this->assertAccessIsGranted($client, \sprintf('/api/actions/activity/%s/%s/en', $activities[0]->getId(), $view));
$result = json_decode($client->getResponse()->getContent(), true);
$this->assertIsArray($result);
@@ -115,7 +115,7 @@ class ActionsControllerTest extends APIControllerBaseTest
$i = 0;
foreach ($entries as $id) {
self::assertEquals($id, $result[$i]['id'], sprintf('Failed action "%s" with name "%s" in view "%s"', $i, $id, $view));
self::assertEquals($id, $result[$i]['id'], \sprintf('Failed action "%s" with name "%s" in view "%s"', $i, $id, $view));
$i++;
}
}
@@ -154,7 +154,7 @@ class ActionsControllerTest extends APIControllerBaseTest
];
foreach ($views as $view => $entries) {
$this->assertAccessIsGranted($client, sprintf('/api/actions/project/%s/%s/en', $projects[0]->getId(), $view));
$this->assertAccessIsGranted($client, \sprintf('/api/actions/project/%s/%s/en', $projects[0]->getId(), $view));
$result = json_decode($client->getResponse()->getContent(), true);
$this->assertIsArray($result);
@@ -164,7 +164,7 @@ class ActionsControllerTest extends APIControllerBaseTest
$i = 0;
foreach ($entries as $id) {
self::assertEquals($id, $result[$i]['id'], sprintf('Failed action "%s" with name "%s" in view "%s"', $i, $id, $view));
self::assertEquals($id, $result[$i]['id'], \sprintf('Failed action "%s" with name "%s" in view "%s"', $i, $id, $view));
$i++;
}
}
@@ -199,7 +199,7 @@ class ActionsControllerTest extends APIControllerBaseTest
];
foreach ($views as $view => $entries) {
$this->assertAccessIsGranted($client, sprintf('/api/actions/customer/%s/%s/en', $customers[0]->getId(), $view));
$this->assertAccessIsGranted($client, \sprintf('/api/actions/customer/%s/%s/en', $customers[0]->getId(), $view));
$result = json_decode($client->getResponse()->getContent(), true);
$this->assertIsArray($result);
@@ -209,7 +209,7 @@ class ActionsControllerTest extends APIControllerBaseTest
$i = 0;
foreach ($entries as $id) {
self::assertEquals($id, $result[$i]['id'], sprintf('Failed action "%s" with name "%s" in view "%s"', $i, $id, $view));
self::assertEquals($id, $result[$i]['id'], \sprintf('Failed action "%s" with name "%s" in view "%s"', $i, $id, $view));
$i++;
}
}

View File

@@ -46,10 +46,10 @@ class ActivityControllerTest extends APIControllerBaseTest
protected function getRateUrl($id = '1', $rateId = null): string
{
if (null !== $rateId) {
return sprintf('/api/activities/%s/rates/%s', $id, $rateId);
return \sprintf('/api/activities/%s/rates/%s', $id, $rateId);
}
return sprintf('/api/activities/%s/rates', $id);
return \sprintf('/api/activities/%s/rates', $id);
}
protected function importTestRates($id): array

View File

@@ -26,7 +26,7 @@ class ApiDocControllerTest extends ControllerBaseTest
{
$client = $this->getClientForAuthenticatedUser(User::ROLE_USER);
$this->assertAccessIsGranted($client, '/api/doc');
$this->assertStringContainsString('<title>Kimai - API Docs</title>', $client->getResponse()->getContent());
$this->assertStringContainsString('<title>Kimai', $client->getResponse()->getContent());
$result = $client->getCrawler()->filter('script#swagger-data');
$swaggerJson = json_decode($result->text(), true);
$tags = [];
@@ -44,7 +44,7 @@ class ApiDocControllerTest extends ControllerBaseTest
sort($actual);
sort($expectedKeys);
self::assertEquals($expectedKeys, $actual, sprintf('Expected %s sections in API docs, but found %s.', \count($actual), \count($expectedKeys)));
self::assertEquals($expectedKeys, $actual, \sprintf('Expected %s sections in API docs, but found %s.', \count($actual), \count($expectedKeys)));
}
public function testGetJsonDocs(): void
@@ -105,7 +105,7 @@ class ApiDocControllerTest extends ControllerBaseTest
$this->assertArrayHasKey('openapi', $json);
$this->assertEquals('3.0.0', $json['openapi']);
$this->assertArrayHasKey('info', $json);
$this->assertEquals('Kimai - API Docs', $json['info']['title']);
$this->assertStringStartsWith('Kimai', $json['info']['title']);
$this->assertEquals('1.0', $json['info']['version']);
$this->assertArrayHasKey('paths', $json);

View File

@@ -70,13 +70,13 @@ class AuthenticationTest extends APIControllerBaseTest
$this->assertEquals(
$data,
json_decode($response->getContent(), true),
sprintf('The secure URL %s is not protected.', $url)
\sprintf('The secure URL %s is not protected.', $url)
);
$this->assertEquals(
Response::HTTP_FORBIDDEN,
$response->getStatusCode(),
sprintf('The secure URL %s has the wrong status code %s.', $url, $response->getStatusCode())
\sprintf('The secure URL %s has the wrong status code %s.', $url, $response->getStatusCode())
);
}

View File

@@ -46,10 +46,10 @@ class CustomerControllerTest extends APIControllerBaseTest
protected function getRateUrl($id = '1', $rateId = null): string
{
if (null !== $rateId) {
return sprintf('/api/customers/%s/rates/%s', $id, $rateId);
return \sprintf('/api/customers/%s/rates/%s', $id, $rateId);
}
return sprintf('/api/customers/%s/rates', $id);
return \sprintf('/api/customers/%s/rates', $id);
}
protected function importTestRates($id): array

View File

@@ -47,10 +47,10 @@ class ProjectControllerTest extends APIControllerBaseTest
protected function getRateUrl($id = '1', $rateId = null): string
{
if (null !== $rateId) {
return sprintf('/api/projects/%s/rates/%s', $id, $rateId);
return \sprintf('/api/projects/%s/rates/%s', $id, $rateId);
}
return sprintf('/api/projects/%s/rates', $id);
return \sprintf('/api/projects/%s/rates', $id);
}
protected function importTestRates($id): array

View File

@@ -419,7 +419,7 @@ class TimesheetControllerTest extends APIControllerBaseTest
];
foreach ($expected as $key => $value) {
self::assertEquals($value, $result[$key], sprintf('Field %s has invalid value', $key));
self::assertEquals($value, $result[$key], \sprintf('Field %s has invalid value', $key));
}
}

View File

@@ -162,12 +162,12 @@ class ExportCreateCommandTest extends KernelTestCase
public function testCreateWithInvalidEmail(): void
{
$this->assertCommandErrors(['--template' => 'csv', '--email' => ['tzuikmnbgtz']], 'Invalid "email" given: tzuikmnbgtz');
$this->assertCommandErrors(['--template' => 'csv', '--email' => ['tzuikmnbgtz']], 'Invalid "email" given');
}
public function testCreateWithInvalidEmails(): void
{
$this->assertCommandErrors(['--template' => 'csv', '--email' => ['foo@example.com', 'foo@1']], 'Invalid "email" given: foo@1');
$this->assertCommandErrors(['--template' => 'csv', '--email' => ['foo@example.com', 'foo@1']], 'Invalid "email" given');
}
public function testCreateWithMissingEntries(): void

View File

@@ -54,7 +54,7 @@ class UpdateCommandTest extends KernelTestCase
self::assertStringContainsString('[OK] Already at the latest version ("DoctrineMigrations\\', $result);
self::assertStringContainsString(
sprintf('[OK] Congratulations! Successfully updated Kimai to version %s', Constants::VERSION),
\sprintf('[OK] Congratulations! Successfully updated Kimai to version %s', Constants::VERSION),
$result
);

View File

@@ -25,6 +25,6 @@ class ConsoleApplicationTest extends TestCase
$sut = new ConsoleApplication($kernel);
self::assertEquals(Constants::SOFTWARE, $sut->getName());
self::assertEquals(Constants::VERSION, $sut->getVersion());
self::assertEquals(sprintf('%s <info>%s</info> (env: <comment></>, debug: <comment>false</>)', Constants::SOFTWARE, Constants::VERSION), $sut->getLongVersion());
self::assertEquals(\sprintf('%s <info>%s</info> (env: <comment></>, debug: <comment>false</>)', Constants::SOFTWARE, Constants::VERSION), $sut->getLongVersion());
}
}

View File

@@ -182,13 +182,13 @@ abstract class ControllerBaseTest extends WebTestCase
self::assertTrue(
$response->isRedirect(),
sprintf('The secure URL %s is not protected.', $url)
\sprintf('The secure URL %s is not protected.', $url)
);
self::assertStringEndsWith(
'/login',
$response->getTargetUrl(),
sprintf('The secure URL %s does not redirect to the login form.', $url)
\sprintf('The secure URL %s does not redirect to the login form.', $url)
);
}
@@ -210,7 +210,7 @@ abstract class ControllerBaseTest extends WebTestCase
$client->request($method, $this->createUrl($url));
self::assertFalse(
$client->getResponse()->isSuccessful(),
sprintf('The secure URL %s is not protected for role %s', $url, $role)
\sprintf('The secure URL %s is not protected for role %s', $url, $role)
);
$this->assertAccessDenied($client);
}
@@ -325,7 +325,7 @@ abstract class ControllerBaseTest extends WebTestCase
self::assertEquals(
\count($fieldNames),
\count($validationErrors),
sprintf('Expected %s validation errors, found %s', \count($fieldNames), \count($validationErrors))
\sprintf('Expected %s validation errors, found %s', \count($fieldNames), \count($validationErrors))
);
foreach ($fieldNames as $name) {
@@ -432,7 +432,7 @@ abstract class ControllerBaseTest extends WebTestCase
self::assertNotNull($location);
// check for meta refresh
$expectedMeta = sprintf('<meta http-equiv="refresh" content="0;url=\'%1$s\'" />', $location);
$expectedMeta = \sprintf('<meta http-equiv="refresh" content="0;url=\'%1$s\'" />', $location);
self::assertStringContainsString($expectedMeta, $client->getResponse()->getContent());
if ($url !== null) {

View File

@@ -243,7 +243,7 @@ class ProfileControllerTest extends ControllerBaseTest
}
/**
* @legacy
* @group legacy
*/
public function testApiTokenAction(): void
{

View File

@@ -53,8 +53,8 @@ abstract class AbstractUserPeriodControllerTest extends ControllerBaseTest
{
$client = $this->getClientForAuthenticatedUser(User::ROLE_SUPER_ADMIN);
$this->importReportingFixture(User::ROLE_SUPER_ADMIN);
$this->assertAccessIsGranted($client, sprintf('%s?user=%s&date=12999119191&sumType=%s', $this->getReportUrl(), $user, $dataType));
self::assertStringContainsString(sprintf('<div class="card-body %s', $this->getBoxId()), $client->getResponse()->getContent());
$this->assertAccessIsGranted($client, \sprintf('%s?user=%s&date=12999119191&sumType=%s', $this->getReportUrl(), $user, $dataType));
self::assertStringContainsString(\sprintf('<div class="card-body %s', $this->getBoxId()), $client->getResponse()->getContent());
$option = $client->getCrawler()->filterXPath("//select[@id='user']/option[@selected]");
self::assertEquals($user, $option->attr('value'));
$cell = $client->getCrawler()->filterXPath("//th[contains(@class, 'reportDataTypeTitle')]");
@@ -65,8 +65,8 @@ abstract class AbstractUserPeriodControllerTest extends ControllerBaseTest
{
$client = $this->getClientForAuthenticatedUser(User::ROLE_USER);
$this->importReportingFixture(User::ROLE_USER);
$this->assertAccessIsGranted($client, sprintf('%s?date=12999119191', $this->getReportUrl()));
self::assertStringContainsString(sprintf('<div class="card-body %s', $this->getBoxId()), $client->getResponse()->getContent());
$this->assertAccessIsGranted($client, \sprintf('%s?date=12999119191', $this->getReportUrl()));
self::assertStringContainsString(\sprintf('<div class="card-body %s', $this->getBoxId()), $client->getResponse()->getContent());
$select = $client->getCrawler()->filterXPath("//select[@id='user']");
self::assertEquals(0, $select->count());
$cell = $client->getCrawler()->filterXPath("//th[contains(@class, 'reportDataTypeTitle')]");

View File

@@ -56,8 +56,8 @@ abstract class AbstractUsersPeriodControllerTest extends ControllerBaseTest
{
$client = $this->getClientForAuthenticatedUser(User::ROLE_SUPER_ADMIN);
$this->importReportingFixture(User::ROLE_SUPER_ADMIN);
$this->assertAccessIsGranted($client, sprintf('%s?date=12999119191&sumType=%s', $this->getReportUrl(), $dataType));
self::assertStringContainsString(sprintf('<div class="card-body %s', $this->getBoxId()), $client->getResponse()->getContent());
$this->assertAccessIsGranted($client, \sprintf('%s?date=12999119191&sumType=%s', $this->getReportUrl(), $dataType));
self::assertStringContainsString(\sprintf('<div class="card-body %s', $this->getBoxId()), $client->getResponse()->getContent());
$cell = $client->getCrawler()->filterXPath("//th[contains(@class, 'reportDataTypeTitle')]");
self::assertEquals($title, $cell->text());
}
@@ -69,8 +69,8 @@ abstract class AbstractUsersPeriodControllerTest extends ControllerBaseTest
{
$client = $this->getClientForAuthenticatedUser(User::ROLE_TEAMLEAD);
$this->importReportingFixture(User::ROLE_TEAMLEAD);
$this->assertAccessIsGranted($client, sprintf('%s?date=12999119191&sumType=%s', $this->getReportUrl(), $dataType));
self::assertStringContainsString(sprintf('<div class="card-body %s', $this->getBoxId()), $client->getResponse()->getContent());
$this->assertAccessIsGranted($client, \sprintf('%s?date=12999119191&sumType=%s', $this->getReportUrl(), $dataType));
self::assertStringContainsString(\sprintf('<div class="card-body %s', $this->getBoxId()), $client->getResponse()->getContent());
$select = $client->getCrawler()->filterXPath("//select[@id='user']");
self::assertEquals(0, $select->count());
$cell = $client->getCrawler()->filterXPath("//th[contains(@class, 'reportDataTypeTitle')]");
@@ -84,7 +84,7 @@ abstract class AbstractUsersPeriodControllerTest extends ControllerBaseTest
{
$client = $this->getClientForAuthenticatedUser(User::ROLE_SUPER_ADMIN);
$this->importReportingFixture(User::ROLE_SUPER_ADMIN);
$this->request($client, sprintf('%s?date=12999119191&sumType=%s', $this->getReportExportUrl(), $dataType));
$this->request($client, \sprintf('%s?date=12999119191&sumType=%s', $this->getReportExportUrl(), $dataType));
$response = $client->getResponse();
$this->assertTrue($response->isSuccessful());
self::assertInstanceOf(BinaryFileResponse::class, $response);

View File

@@ -52,8 +52,8 @@ trait EntityValidationTestTrait
$this->assertTrue($foundField, 'Failed finding violation for field: ' . $propertyPath);
}
$this->assertEmpty($violatedFields, sprintf('Unexpected violations found: %s', implode(', ', $violatedFields)));
$this->assertEquals($expected, $countViolations, sprintf('Expected %s violations, found %s in %s.', $expected, $actual, implode(', ', array_keys($violatedFields))));
$this->assertEmpty($violatedFields, \sprintf('Unexpected violations found: %s', implode(', ', $violatedFields)));
$this->assertEquals($expected, $countViolations, \sprintf('Expected %s violations, found %s in %s.', $expected, $actual, implode(', ', array_keys($violatedFields))));
}
public function assertHasNoViolations($entity, $groups = null): void
@@ -65,6 +65,6 @@ trait EntityValidationTestTrait
$violations = $validator->validate($entity, null, $groups);
$actual = $violations->count();
$this->assertEquals(0, $actual, sprintf('Expected 0 violations, found %s.', $actual));
$this->assertEquals(0, $actual, \sprintf('Expected 0 violations, found %s.', $actual));
}
}

View File

@@ -238,7 +238,7 @@ class ConfigurableNumberGeneratorTest extends TestCase
public function testInvalidGetInvoiceNumber(string $format, \DateTime $invoiceDate, string $brokenPart): void
{
$this->expectException(\InvalidArgumentException::class);
$this->expectExceptionMessage(sprintf('Unknown %s found', $brokenPart));
$this->expectExceptionMessage(\sprintf('Unknown %s found', $brokenPart));
$sut = $this->getSut($format);
$model = (new InvoiceModelFactoryFactory($this))->create()->createModel(new DebugFormatter(), new Customer('foo'), new InvoiceTemplate(), new InvoiceQuery());

View File

@@ -228,7 +228,7 @@ class LdapManagerTest extends TestCase
return $expected[1];
}
$this->fail(sprintf('Unexpected search with baseDn %s', $baseDn));
$this->fail(\sprintf('Unexpected search with baseDn %s', $baseDn));
});
$sut = $this->getLdapManager($driver);
@@ -269,7 +269,7 @@ class LdapManagerTest extends TestCase
return $expected[1];
}
$this->fail(sprintf('Unexpected search with baseDn %s', $baseDn));
$this->fail(\sprintf('Unexpected search with baseDn %s', $baseDn));
});
$sut = $this->getLdapManager($driver);
@@ -305,7 +305,7 @@ class LdapManagerTest extends TestCase
return $expected[1];
}
$this->fail(sprintf('Unexpected search with baseDn %s', $baseDn));
$this->fail(\sprintf('Unexpected search with baseDn %s', $baseDn));
});
$sut = $this->getLdapManager($driver, [
@@ -445,7 +445,7 @@ class LdapManagerTest extends TestCase
return $expectedGroups;
}
$this->fail(sprintf('Unexpected search with baseDn %s', $baseDn));
$this->fail(\sprintf('Unexpected search with baseDn %s', $baseDn));
});
$sut = $this->getLdapManager($driver, $groupConfig);

View File

@@ -23,9 +23,9 @@ class MonthTest extends TestCase
foreach($months as $key => $days) {
$index = ++$key;
$monthKey = ($index < 10) ? '0' . $index : $index;
$date = new \DateTimeImmutable(sprintf('2020-%s-25 13:00:00', $monthKey));
$date = new \DateTimeImmutable(\sprintf('2020-%s-25 13:00:00', $monthKey));
$month = new Month($date);
self::assertEquals(sprintf('2020-%s-25', $monthKey), $month->getMonth()->format('Y-m-d'));
self::assertEquals(\sprintf('2020-%s-25', $monthKey), $month->getMonth()->format('Y-m-d'));
self::assertCount($days, $month->getDays());
}
}

View File

@@ -27,8 +27,8 @@ class YearTest extends TestCase
foreach($months as $key => $days) {
$index = ++$key;
$monthKey = ($index < 10) ? '0' . $index : $index;
$month = $sut->getMonth(new \DateTimeImmutable(sprintf('2020-%s-13 13:00:00', $monthKey)));
self::assertEquals(sprintf('2020-%s-01', $monthKey), $month->getMonth()->format('Y-m-d'));
$month = $sut->getMonth(new \DateTimeImmutable(\sprintf('2020-%s-13 13:00:00', $monthKey)));
self::assertEquals(\sprintf('2020-%s-01', $monthKey), $month->getMonth()->format('Y-m-d'));
self::assertCount($days, $month->getDays());
}
}

View File

@@ -36,7 +36,7 @@ class TranslationsTest extends TestCase
foreach ($body->children() as $transUnit) {
self::assertNotEmpty(
(string) $transUnit->target,
sprintf(
\sprintf(
'Found empty translation in language "%s" and file "%s" for key "%s"',
$xml->file->attributes()['target-language'],
basename($file),
@@ -88,14 +88,14 @@ class TranslationsTest extends TestCase
// some special cases, which don't work properly - base translation should be changed
preg_match_all('/%[a-zA-Z]{1,}%/Uu', (string) $transUnit->target, $matches);
asort($matches[0]);
self::assertEquals($transLang[$key], array_values($matches[0]), sprintf('Invalid replacer "%s" in "%s"', $key, basename($file)));
self::assertEquals($transLang[$key], array_values($matches[0]), \sprintf('Invalid replacer "%s" in "%s"', $key, basename($file)));
$counter++;
unset($transLang[$key]);
}
}
$counter += \count($transLang);
self::assertEquals($expectedCounter, $counter, sprintf('Missing replacer in "%s", did not find translation keys: %s', basename($file), implode(', ', array_keys($transLang))));
self::assertEquals($expectedCounter, $counter, \sprintf('Missing replacer in "%s", did not find translation keys: %s', basename($file), implode(', ', array_keys($transLang))));
}
}
}

View File

@@ -98,7 +98,7 @@ class FormFormatConverterTest extends TestCase
$sut = new FormFormatConverter();
foreach ($this->getPossibleDateTimePattern() as $format => $example) {
$pattern = $sut->convertToPattern($format, false);
$this->assertMatchesRegularExpression($pattern, $example, sprintf('Invalid pattern %s for format %s, did not match %s', $pattern, $format, $example));
$this->assertMatchesRegularExpression($pattern, $example, \sprintf('Invalid pattern %s for format %s, did not match %s', $pattern, $format, $example));
}
}

View File

@@ -27,7 +27,7 @@ class CustomerVoterTest extends AbstractVoterTest
$sut = $this->getVoter(CustomerVoter::class);
$actual = $sut->vote($token, $subject, [$attribute]);
$this->assertEquals($result, $actual, sprintf('Failed voting "%s" for User with roles %s.', $attribute, implode(', ', $user->getRoles())));
$this->assertEquals($result, $actual, \sprintf('Failed voting "%s" for User with roles %s.', $attribute, implode(', ', $user->getRoles())));
}
public function testVote(): void

View File

@@ -32,7 +32,7 @@ class ProjectVoterTest extends AbstractVoterTest
}
$actual = $sut->vote($token, $subject, [$attribute]);
$this->assertEquals($result, $actual, sprintf('Failed voting "%s" for User with roles %s.', $attribute, implode(', ', $user->getRoles())));
$this->assertEquals($result, $actual, \sprintf('Failed voting "%s" for User with roles %s.', $attribute, implode(', ', $user->getRoles())));
}
public function testVote(): void

View File

@@ -29,7 +29,7 @@ class RolePermissionVoterTest extends AbstractVoterTest
$sut = $this->getVoter(RolePermissionVoter::class);
$actual = $sut->vote($token, $subject, [$attribute]);
$this->assertEquals($result, $actual, sprintf('Failed voting "%s" for User with roles %s.', $attribute, implode(', ', $user->getRoles())));
$this->assertEquals($result, $actual, \sprintf('Failed voting "%s" for User with roles %s.', $attribute, implode(', ', $user->getRoles())));
}
public function getTestData()

Some files were not shown because too many files have changed in this diff Show More