Release 2.0.9 (#3922)

* fix api definition
* include customer number in validation message
* fix doctrine deprecation, prepare for DBAL 4
* added DataSubscriberInterface to identify certain doctrine subscribers
This commit is contained in:
Kevin Papst
2023-03-14 23:51:49 +01:00
committed by GitHub
parent 8449eafcb6
commit 1a8c78944a
15 changed files with 50 additions and 75 deletions

View File

@@ -29,20 +29,20 @@ final class Version20190706224211 extends AbstractMigration
public function up(Schema $schema): void public function up(Schema $schema): void
{ {
$timesheetMeta = $schema->getTable('kimai2_timesheet_meta'); $timesheetMeta = $schema->getTable('kimai2_timesheet_meta');
$timesheetMeta->changeColumn('visible', ['notnull' => true, 'default' => false]); $timesheetMeta->modifyColumn('visible', ['notnull' => true, 'default' => false]);
$timesheetMeta->changeColumn('timesheet_id', ['notnull' => true]); $timesheetMeta->modifyColumn('timesheet_id', ['notnull' => true]);
$projectMeta = $schema->getTable('kimai2_projects_meta'); $projectMeta = $schema->getTable('kimai2_projects_meta');
$projectMeta->changeColumn('visible', ['notnull' => true, 'default' => false]); $projectMeta->modifyColumn('visible', ['notnull' => true, 'default' => false]);
$projectMeta->changeColumn('project_id', ['notnull' => true]); $projectMeta->modifyColumn('project_id', ['notnull' => true]);
$customerMeta = $schema->getTable('kimai2_customers_meta'); $customerMeta = $schema->getTable('kimai2_customers_meta');
$customerMeta->changeColumn('visible', ['notnull' => true, 'default' => false]); $customerMeta->modifyColumn('visible', ['notnull' => true, 'default' => false]);
$customerMeta->changeColumn('customer_id', ['notnull' => true]); $customerMeta->modifyColumn('customer_id', ['notnull' => true]);
$activityMeta = $schema->getTable('kimai2_activities_meta'); $activityMeta = $schema->getTable('kimai2_activities_meta');
$activityMeta->changeColumn('visible', ['notnull' => true, 'default' => false]); $activityMeta->modifyColumn('visible', ['notnull' => true, 'default' => false]);
$activityMeta->changeColumn('activity_id', ['notnull' => true]); $activityMeta->modifyColumn('activity_id', ['notnull' => true]);
} }
public function down(Schema $schema): void public function down(Schema $schema): void

View File

@@ -51,7 +51,7 @@ final class Version20210802152814 extends AbstractMigration
public function down(Schema $schema): void public function down(Schema $schema): void
{ {
$timesheet = $schema->getTable('kimai2_timesheet'); $timesheet = $schema->getTable('kimai2_timesheet');
$timesheet->changeColumn('date_tz', ['notnull' => false]); $timesheet->modifyColumn('date_tz', ['notnull' => false]);
$this->preventEmptyMigrationWarning(); $this->preventEmptyMigrationWarning();
} }

View File

@@ -27,14 +27,14 @@ final class Version20210802160837 extends AbstractMigration
public function up(Schema $schema): void public function up(Schema $schema): void
{ {
$timesheet = $schema->getTable('kimai2_timesheet'); $timesheet = $schema->getTable('kimai2_timesheet');
$timesheet->changeColumn('date_tz', ['notnull' => true]); $timesheet->modifyColumn('date_tz', ['notnull' => true]);
$timesheet->addIndex(['date_tz', 'user'], 'IDX_4F60C6B1BDF467148D93D649'); $timesheet->addIndex(['date_tz', 'user'], 'IDX_4F60C6B1BDF467148D93D649');
} }
public function down(Schema $schema): void public function down(Schema $schema): void
{ {
$timesheet = $schema->getTable('kimai2_timesheet'); $timesheet = $schema->getTable('kimai2_timesheet');
$timesheet->changeColumn('date_tz', ['notnull' => false]); $timesheet->modifyColumn('date_tz', ['notnull' => false]);
$timesheet->dropIndex('IDX_4F60C6B1BDF467148D93D649'); $timesheet->dropIndex('IDX_4F60C6B1BDF467148D93D649');
} }
} }

View File

@@ -11,6 +11,7 @@ namespace App\Command;
use App\Constants; use App\Constants;
use Doctrine\DBAL\Connection; use Doctrine\DBAL\Connection;
use Doctrine\DBAL\Exception\ConnectionException;
use Symfony\Component\Console\Attribute\AsCommand; use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\ArrayInput; use Symfony\Component\Console\Input\ArrayInput;
@@ -47,12 +48,6 @@ final class UpdateCommand extends Command
// make sure database is available, Kimai running and installed // make sure database is available, Kimai running and installed
try { try {
if (!$this->connection->isConnected() && !$this->connection->connect()) {
throw new \Exception(
sprintf('Database connection could not be established: %s', $this->connection->getDatabase())
);
}
if (!$this->connection->createSchemaManager()->tablesExist(['kimai2_users', 'kimai2_timesheet'])) { if (!$this->connection->createSchemaManager()->tablesExist(['kimai2_users', 'kimai2_timesheet'])) {
$io->error('Tables missing. Did you run the installer already?'); $io->error('Tables missing. Did you run the installer already?');
@@ -64,8 +59,12 @@ final class UpdateCommand extends Command
return Command::FAILURE; return Command::FAILURE;
} }
} catch (ConnectionException $e) {
$io->error(['Database connection could not be established.', $e->getMessage()]);
return Command::FAILURE;
} catch (\Exception $ex) { } catch (\Exception $ex) {
$io->error('Failed to validate database: ' . $ex->getMessage()); $io->error(['Failed to validate database.', $ex->getMessage()]);
return Command::FAILURE; return Command::FAILURE;
} }

View File

@@ -17,11 +17,11 @@ class Constants
/** /**
* The current release version * The current release version
*/ */
public const VERSION = '2.0.8'; public const VERSION = '2.0.9';
/** /**
* The current release: major * 10000 + minor * 100 + patch * The current release: major * 10000 + minor * 100 + patch
*/ */
public const VERSION_ID = 20008; public const VERSION_ID = 20009;
/** /**
* The software name * The software name
*/ */

View File

@@ -0,0 +1,18 @@
<?php
/*
* This file is part of the Kimai time-tracking app.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace App\Doctrine;
/**
* Used to identify EventSubscribers, that work upon EntityManager events and listen on data changes.
* These Subscribers will deactivated on batch imports, for performance gains and reduced DB queries.
*/
interface DataSubscriberInterface
{
}

View File

@@ -16,9 +16,9 @@ use Doctrine\ORM\Event\OnFlushEventArgs;
use Doctrine\ORM\Events; use Doctrine\ORM\Events;
/** /**
* A listener to make sure all Timesheet entries will have a proper duration. * A listener to make sure all Timesheet entries will be calculated properly (e.g. duration and rates).
*/ */
final class TimesheetSubscriber implements EventSubscriber final class TimesheetSubscriber implements EventSubscriber, DataSubscriberInterface
{ {
/** /**
* @var CalculatorInterface[] * @var CalculatorInterface[]

View File

@@ -74,9 +74,4 @@ final class UTCDateTimeType extends DateTimeType
return $converted; return $converted;
} }
public function requiresSQLCommentHint(AbstractPlatform $platform): bool
{
return true;
}
} }

View File

@@ -47,7 +47,7 @@ class Activity implements EntityWithMetaFields, EntityWithBudget
#[ORM\JoinColumn(onDelete: 'CASCADE')] #[ORM\JoinColumn(onDelete: 'CASCADE')]
#[Serializer\Expose] #[Serializer\Expose]
#[Serializer\Groups(['Subresource', 'Expanded'])] #[Serializer\Groups(['Subresource', 'Expanded'])]
#[OA\Property(ref: '#/components/schemas/Project')] #[OA\Property(ref: '#/components/schemas/ProjectExpanded')]
private ?Project $project = null; private ?Project $project = null;
/** /**
* Name of this activity * Name of this activity

View File

@@ -140,7 +140,7 @@ class User implements UserInterface, EquatableInterface, ThemeUserInterface, Pas
#[Assert\NotNull] #[Assert\NotNull]
#[Serializer\Expose] #[Serializer\Expose]
#[Serializer\Groups(['User_Entity'])] #[Serializer\Groups(['User_Entity'])]
#[OA\Property(ref: '#/components/schemas/TeamMembership')] #[OA\Property(type: 'array', items: new OA\Items(ref: '#/components/schemas/TeamMembership'))]
private Collection $memberships; private Collection $memberships;
/** /**
* The type of authentication used by the user (e.g. "kimai", "ldap", "saml") * The type of authentication used by the user (e.g. "kimai", "ldap", "saml")

View File

@@ -81,7 +81,7 @@ class UserService
$this->hashPassword($user); $this->hashPassword($user);
$this->hashApiToken($user); $this->hashApiToken($user);
$this->dispatcher->dispatch(new UserCreatePreEvent($user)); $this->dispatcher->dispatch(new UserCreatePreEvent($user)); // @CloudRequired
$this->repository->saveUser($user); $this->repository->saveUser($user);
$this->dispatcher->dispatch(new UserCreatePostEvent($user)); $this->dispatcher->dispatch(new UserCreatePostEvent($user));

View File

@@ -17,7 +17,7 @@ final class Customer extends Constraint
public const CUSTOMER_NUMBER_EXISTING = 'kimai-customer-00'; public const CUSTOMER_NUMBER_EXISTING = 'kimai-customer-00';
protected const ERROR_NAMES = [ protected const ERROR_NAMES = [
self::CUSTOMER_NUMBER_EXISTING => 'This account number is already used.', self::CUSTOMER_NUMBER_EXISTING => 'The account number %number% is already used.',
]; ];
public string $message = 'This customer has invalid settings.'; public string $message = 'This customer has invalid settings.';

View File

@@ -40,6 +40,7 @@ final class CustomerValidator extends ConstraintValidator
$tmp = $this->customerRepository->findOneBy(['number' => $number]); $tmp = $this->customerRepository->findOneBy(['number' => $number]);
if ($tmp !== null && $tmp->getId() !== $value->getId()) { if ($tmp !== null && $tmp->getId() !== $value->getId()) {
$this->context->buildViolation(Customer::getErrorName(Customer::CUSTOMER_NUMBER_EXISTING)) $this->context->buildViolation(Customer::getErrorName(Customer::CUSTOMER_NUMBER_EXISTING))
->setParameter('%number%', $number)
->atPath('number') ->atPath('number')
->setTranslationDomain('validators') ->setTranslationDomain('validators')
->setCode(Customer::CUSTOMER_NUMBER_EXISTING) ->setCode(Customer::CUSTOMER_NUMBER_EXISTING)

View File

@@ -22,7 +22,7 @@ use PHPUnit\Framework\TestCase;
*/ */
class UTCDateTimeTypeTest extends TestCase class UTCDateTimeTypeTest extends TestCase
{ {
public function testGetUtc() public function testGetUtc(): void
{ {
Type::overrideType(Types::DATETIME_MUTABLE, UTCDateTimeType::class); Type::overrideType(Types::DATETIME_MUTABLE, UTCDateTimeType::class);
/** @var UTCDateTimeType $type */ /** @var UTCDateTimeType $type */
@@ -37,7 +37,7 @@ class UTCDateTimeTypeTest extends TestCase
/** /**
* @dataProvider getPlatforms * @dataProvider getPlatforms
*/ */
public function testConvertToDatabaseValue(AbstractPlatform $platform) public function testConvertToDatabaseValue(AbstractPlatform $platform): void
{ {
Type::overrideType(Types::DATETIME_MUTABLE, UTCDateTimeType::class); Type::overrideType(Types::DATETIME_MUTABLE, UTCDateTimeType::class);
/** @var UTCDateTimeType $type */ /** @var UTCDateTimeType $type */
@@ -65,7 +65,7 @@ class UTCDateTimeTypeTest extends TestCase
/** /**
* @dataProvider getPlatforms * @dataProvider getPlatforms
*/ */
public function testConvertToPHPValue(AbstractPlatform $platform) public function testConvertToPHPValue(AbstractPlatform $platform): void
{ {
Type::overrideType(Types::DATETIME_MUTABLE, UTCDateTimeType::class); Type::overrideType(Types::DATETIME_MUTABLE, UTCDateTimeType::class);
/** @var UTCDateTimeType $type */ /** @var UTCDateTimeType $type */
@@ -85,7 +85,7 @@ class UTCDateTimeTypeTest extends TestCase
/** /**
* @dataProvider getPlatforms * @dataProvider getPlatforms
*/ */
public function testConvertToPHPValueWithInvalidValue(AbstractPlatform $platform) public function testConvertToPHPValueWithInvalidValue(AbstractPlatform $platform): void
{ {
$this->expectException(ConversionException::class); $this->expectException(ConversionException::class);
@@ -97,17 +97,9 @@ class UTCDateTimeTypeTest extends TestCase
} }
/** /**
* @dataProvider getPlatforms * @return \Doctrine\DBAL\Platforms\MySQLPlatform[][]
*/ */
public function testRequiresSQLCommentHint(AbstractPlatform $platform) public function getPlatforms(): array
{
Type::overrideType(Types::DATETIME_MUTABLE, UTCDateTimeType::class);
/** @var UTCDateTimeType $type */
$type = Type::getType(Types::DATETIME_MUTABLE);
self::assertTrue($type->requiresSQLCommentHint($platform));
}
public function getPlatforms()
{ {
return [ return [
[new MySQLPlatform()], [new MySQLPlatform()],

View File

@@ -4727,36 +4727,6 @@ parameters:
count: 1 count: 1
path: Doctrine/TimesheetSubscriberTest.php path: Doctrine/TimesheetSubscriberTest.php
-
message: "#^Method App\\\\Tests\\\\Doctrine\\\\UTCDateTimeTypeTest\\:\\:getPlatforms\\(\\) has no return type specified\\.$#"
count: 1
path: Doctrine/UTCDateTimeTypeTest.php
-
message: "#^Method App\\\\Tests\\\\Doctrine\\\\UTCDateTimeTypeTest\\:\\:testConvertToDatabaseValue\\(\\) has no return type specified\\.$#"
count: 1
path: Doctrine/UTCDateTimeTypeTest.php
-
message: "#^Method App\\\\Tests\\\\Doctrine\\\\UTCDateTimeTypeTest\\:\\:testConvertToPHPValue\\(\\) has no return type specified\\.$#"
count: 1
path: Doctrine/UTCDateTimeTypeTest.php
-
message: "#^Method App\\\\Tests\\\\Doctrine\\\\UTCDateTimeTypeTest\\:\\:testConvertToPHPValueWithInvalidValue\\(\\) has no return type specified\\.$#"
count: 1
path: Doctrine/UTCDateTimeTypeTest.php
-
message: "#^Method App\\\\Tests\\\\Doctrine\\\\UTCDateTimeTypeTest\\:\\:testGetUtc\\(\\) has no return type specified\\.$#"
count: 1
path: Doctrine/UTCDateTimeTypeTest.php
-
message: "#^Method App\\\\Tests\\\\Doctrine\\\\UTCDateTimeTypeTest\\:\\:testRequiresSQLCommentHint\\(\\) has no return type specified\\.$#"
count: 1
path: Doctrine/UTCDateTimeTypeTest.php
- -
message: "#^Method App\\\\Tests\\\\Entity\\\\AbstractCommentEntityTest\\:\\:testDefaultValues\\(\\) has no return type specified\\.$#" message: "#^Method App\\\\Tests\\\\Entity\\\\AbstractCommentEntityTest\\:\\:testDefaultValues\\(\\) has no return type specified\\.$#"
count: 1 count: 1