Release 2.33.0 (#5438)
This commit is contained in:
@@ -120,12 +120,23 @@ class ActivityService
|
||||
// we cannot use max(number) because a varchar column returns unexpected results
|
||||
$start = $this->repository->countActivity();
|
||||
$i = 0;
|
||||
$createDate = new \DateTimeImmutable();
|
||||
|
||||
do {
|
||||
$start++;
|
||||
|
||||
$numberGenerator = new NumberGenerator($format, function (string $originalFormat, string $format, int $increaseBy) use ($start): string|int {
|
||||
$numberGenerator = new NumberGenerator($format, function (string $originalFormat, string $format, int $increaseBy) use ($start, $createDate): string|int {
|
||||
return match ($format) {
|
||||
'Y' => $createDate->format('Y'),
|
||||
'y' => $createDate->format('y'),
|
||||
'M' => $createDate->format('m'),
|
||||
'm' => $createDate->format('n'),
|
||||
'D' => $createDate->format('d'),
|
||||
'd' => $createDate->format('j'),
|
||||
'YY' => (int) $createDate->format('Y') + $increaseBy,
|
||||
'yy' => (int) $createDate->format('y') + $increaseBy,
|
||||
'MM' => (int) $createDate->format('m') + $increaseBy,
|
||||
'DD' => (int) $createDate->format('d') + $increaseBy,
|
||||
'ac' => $start + $increaseBy,
|
||||
default => $originalFormat,
|
||||
};
|
||||
|
||||
@@ -39,7 +39,7 @@ final class RegenerateLocalesCommand extends Command
|
||||
*
|
||||
* @var string[]
|
||||
*/
|
||||
private array $noRegionCode = ['ar', 'id', 'pa', 'sl', 'ca'];
|
||||
private array $noRegionCode = ['ar', 'id', 'pa', 'sl', 'ca', 'ta'];
|
||||
/**
|
||||
* A list of locales that will be activated, no matter if translation files exist for them.
|
||||
*
|
||||
@@ -47,11 +47,11 @@ final class RegenerateLocalesCommand extends Command
|
||||
*/
|
||||
private array $addLocaleToList = ['zh_Hant_TW'];
|
||||
/**
|
||||
* A list of locales that will NOT be activated, as no translations exist by now.
|
||||
* A list of locales that will NOT be activated, as not enough translations exist by now.
|
||||
*
|
||||
* @var string[]
|
||||
*/
|
||||
private array $skipLocale = ['ca'];
|
||||
private array $skipLocale = ['ca', 'et'];
|
||||
|
||||
public function __construct(
|
||||
private readonly string $projectDirectory,
|
||||
@@ -86,6 +86,7 @@ final class RegenerateLocalesCommand extends Command
|
||||
$firstLevelLocales[] = $l;
|
||||
}
|
||||
$firstLevelLocales = array_unique(array_merge($firstLevelLocales, $this->addLocaleToList));
|
||||
|
||||
$io->title('First level locales found');
|
||||
$io->writeln(implode('|', $firstLevelLocales));
|
||||
|
||||
@@ -198,8 +199,23 @@ final class RegenerateLocalesCommand extends Command
|
||||
|
||||
// in the future this list should be reduced to the list of available translations, but for a long time users
|
||||
// could choose from the entire list of all locales, so we likely have to keep that forever ...
|
||||
$io->title('List of "kimai_locales" for services.yaml');
|
||||
$io->writeln("['" . implode("', '", $locales) . "']");
|
||||
$listOfLocales = array_map(fn ($locale) => "'$locale'", $locales);
|
||||
$filename = 'config/services.yaml';
|
||||
$targetFile = $this->projectDirectory . DIRECTORY_SEPARATOR . $filename;
|
||||
$content = file_get_contents($targetFile);
|
||||
if ($content === false) {
|
||||
$io->error('Failed reading configuration file at ' . $filename);
|
||||
} else {
|
||||
$content = preg_replace(
|
||||
'/^(\s*kimai_locales:\s*\[).*?(\])$/m',
|
||||
'${1}' . implode(', ', $listOfLocales) . '${2}',
|
||||
$content
|
||||
);
|
||||
|
||||
file_put_contents($targetFile, $content);
|
||||
|
||||
$io->success('Replaced locale definitions in: ' . $filename);
|
||||
}
|
||||
|
||||
ksort($appLocales);
|
||||
|
||||
|
||||
@@ -17,11 +17,11 @@ final class Constants
|
||||
/**
|
||||
* The current release version
|
||||
*/
|
||||
public const VERSION = '2.32.0';
|
||||
public const VERSION = '2.33.0';
|
||||
/**
|
||||
* The current release: major * 10000 + minor * 100 + patch
|
||||
*/
|
||||
public const VERSION_ID = 23200;
|
||||
public const VERSION_ID = 23300;
|
||||
/**
|
||||
* The software name
|
||||
*/
|
||||
|
||||
@@ -63,6 +63,8 @@ final class ContractController extends AbstractController
|
||||
|
||||
/** @var \DateTime $yearDate */
|
||||
$yearDate = $values->getDate();
|
||||
// make sure we use the correct datetime for the selected user
|
||||
$yearDate = $this->getDateTimeFactory($profile)->createStartOfYear($yearDate);
|
||||
$year = $workingTimeService->getYear($profile, $yearDate, $now);
|
||||
|
||||
$page = new PageSetup('work_times');
|
||||
|
||||
@@ -137,12 +137,23 @@ final class CustomerService
|
||||
// we cannot use max(number) because a varchar column returns unexpected results
|
||||
$start = $this->repository->countCustomer();
|
||||
$i = 0;
|
||||
$createDate = new \DateTimeImmutable();
|
||||
|
||||
do {
|
||||
$start++;
|
||||
|
||||
$numberGenerator = new NumberGenerator($format, function (string $originalFormat, string $format, int $increaseBy) use ($start): string|int {
|
||||
$numberGenerator = new NumberGenerator($format, function (string $originalFormat, string $format, int $increaseBy) use ($start, $createDate): string|int {
|
||||
return match ($format) {
|
||||
'Y' => $createDate->format('Y'),
|
||||
'y' => $createDate->format('y'),
|
||||
'M' => $createDate->format('m'),
|
||||
'm' => $createDate->format('n'),
|
||||
'D' => $createDate->format('d'),
|
||||
'd' => $createDate->format('j'),
|
||||
'YY' => (int) $createDate->format('Y') + $increaseBy,
|
||||
'yy' => (int) $createDate->format('y') + $increaseBy,
|
||||
'MM' => (int) $createDate->format('m') + $increaseBy,
|
||||
'DD' => (int) $createDate->format('d') + $increaseBy,
|
||||
'cc' => $start + $increaseBy,
|
||||
default => $originalFormat,
|
||||
};
|
||||
|
||||
@@ -12,6 +12,7 @@ namespace App\Export\Base;
|
||||
use App\Entity\ExportableItem;
|
||||
use App\Export\ExportFilename;
|
||||
use App\Export\Package\CellFormatter\DateStringFormatter;
|
||||
use App\Export\Package\CellFormatter\DurationPlainFormatter;
|
||||
use App\Export\Package\SpoutSpreadsheet;
|
||||
use App\Export\RendererInterface;
|
||||
use App\Export\TimesheetExportInterface;
|
||||
@@ -71,6 +72,7 @@ final class CsvRenderer implements RendererInterface, TimesheetExportInterface
|
||||
$spreadsheet->open($filename);
|
||||
|
||||
$this->spreadsheetRenderer->registerFormatter('date', new DateStringFormatter());
|
||||
$this->spreadsheetRenderer->registerFormatter('duration', new DurationPlainFormatter());
|
||||
$this->spreadsheetRenderer->writeSpreadsheet($spreadsheet, $exportItems, $query);
|
||||
|
||||
return new \SplFileInfo($filename);
|
||||
|
||||
@@ -105,7 +105,7 @@ final class SpreadsheetRenderer
|
||||
$formula = null;
|
||||
if (\in_array($column->getName(), $totalColumns)) {
|
||||
$columnName = $columnNames[$totalColumn - 1];
|
||||
$formula = \sprintf('=SUM(%s2:%s%s)', $columnName, $columnName, $currentRow);
|
||||
$formula = \sprintf('=SUBTOTAL(9,%s2:%s%s)', $columnName, $columnName, $currentRow);
|
||||
}
|
||||
$totalRow[] = $formula;
|
||||
$totalColumn++;
|
||||
|
||||
15
src/Export/Package/CellFormatter/CellWithFormatInterface.php
Normal file
15
src/Export/Package/CellFormatter/CellWithFormatInterface.php
Normal file
@@ -0,0 +1,15 @@
|
||||
<?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\Export\Package\CellFormatter;
|
||||
|
||||
interface CellWithFormatInterface
|
||||
{
|
||||
public function getFormat(): string;
|
||||
}
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
namespace App\Export\Package\CellFormatter;
|
||||
|
||||
final class DateFormatter implements CellFormatterInterface
|
||||
final class DateFormatter implements CellFormatterInterface, CellWithFormatInterface
|
||||
{
|
||||
public function formatValue(mixed $value): mixed
|
||||
{
|
||||
@@ -23,4 +23,9 @@ final class DateFormatter implements CellFormatterInterface
|
||||
|
||||
throw new \InvalidArgumentException('Only DateTimeInterface can be formatted');
|
||||
}
|
||||
|
||||
public function getFormat(): string
|
||||
{
|
||||
return 'yyyy-mm-dd';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,23 +9,34 @@
|
||||
|
||||
namespace App\Export\Package\CellFormatter;
|
||||
|
||||
use App\Utils\Duration;
|
||||
|
||||
final class DurationFormatter implements CellFormatterInterface
|
||||
final class DurationFormatter implements CellFormatterInterface, CellWithFormatInterface
|
||||
{
|
||||
private Duration $duration;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->duration = new Duration();
|
||||
}
|
||||
|
||||
public function formatValue(mixed $value): mixed
|
||||
{
|
||||
if (is_numeric($value)) {
|
||||
return $this->duration->format((int) $value);
|
||||
if (!is_numeric($value) || (int) $value === 0) {
|
||||
return new \DateInterval('PT0S');
|
||||
}
|
||||
|
||||
return $this->duration->format(0);
|
||||
$value = (int) $value;
|
||||
|
||||
$seconds = abs($value);
|
||||
$hours = intdiv($seconds, 3600);
|
||||
$seconds %= 3600;
|
||||
$minutes = intdiv($seconds, 60);
|
||||
$seconds %= 60;
|
||||
|
||||
$intervalSpec = \sprintf('PT%dH%dM%dS', $hours, $minutes, $seconds);
|
||||
$interval = new \DateInterval($intervalSpec);
|
||||
|
||||
if ($value < 0) {
|
||||
$interval->invert = 1;
|
||||
}
|
||||
|
||||
return $interval;
|
||||
}
|
||||
|
||||
public function getFormat(): string
|
||||
{
|
||||
return '[hh]:mm:ss';
|
||||
}
|
||||
}
|
||||
|
||||
37
src/Export/Package/CellFormatter/DurationPlainFormatter.php
Normal file
37
src/Export/Package/CellFormatter/DurationPlainFormatter.php
Normal file
@@ -0,0 +1,37 @@
|
||||
<?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\Export\Package\CellFormatter;
|
||||
|
||||
final class DurationPlainFormatter implements CellFormatterInterface
|
||||
{
|
||||
public function formatValue(mixed $value): mixed
|
||||
{
|
||||
if (!is_numeric($value) || (int) $value === 0) {
|
||||
return '0:00:00';
|
||||
}
|
||||
|
||||
$value = (int) $value;
|
||||
|
||||
$seconds = abs($value);
|
||||
$hours = intdiv($seconds, 3600);
|
||||
$seconds %= 3600;
|
||||
$minutes = intdiv($seconds, 60);
|
||||
$seconds %= 60;
|
||||
|
||||
$intervalSpec = \sprintf('PT%dH%dM%dS', $hours, $minutes, $seconds);
|
||||
$interval = new \DateInterval($intervalSpec);
|
||||
|
||||
if ($value < 0) {
|
||||
$interval->invert = 1;
|
||||
}
|
||||
|
||||
return $interval->format('%r%h:%I:%S');
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,7 @@ namespace App\Export\Package;
|
||||
|
||||
use App\Entity\ExportableItem;
|
||||
use App\Export\Package\CellFormatter\CellFormatterInterface;
|
||||
use App\Export\Package\CellFormatter\CellWithFormatInterface;
|
||||
|
||||
class Column
|
||||
{
|
||||
@@ -71,4 +72,13 @@ class Column
|
||||
{
|
||||
return $this->header ?? $this->name;
|
||||
}
|
||||
|
||||
public function getFormat(): ?string
|
||||
{
|
||||
if ($this->formatter instanceof CellWithFormatInterface) {
|
||||
return $this->formatter->getFormat();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,8 @@ use Symfony\Contracts\Translation\TranslatorInterface;
|
||||
|
||||
class SpoutSpreadsheet implements SpreadsheetPackage
|
||||
{
|
||||
private Style $dateStyle;
|
||||
/** @var array<int, Style|null> */
|
||||
private array $styles = [];
|
||||
|
||||
public function __construct(
|
||||
private readonly WriterInterface $writer,
|
||||
@@ -34,7 +35,6 @@ class SpoutSpreadsheet implements SpreadsheetPackage
|
||||
)
|
||||
{
|
||||
$this->writer->setCreator(Constants::SOFTWARE);
|
||||
$this->dateStyle = (new Style())->setFormat('yyyy-mm-dd');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -48,9 +48,15 @@ class SpoutSpreadsheet implements SpreadsheetPackage
|
||||
}
|
||||
|
||||
$tmp = [];
|
||||
$i = 0;
|
||||
foreach ($columns as $column) {
|
||||
$title = $this->translator->trans($column->getHeader());
|
||||
$tmp[] = Cell::fromValue($title);
|
||||
$style = null;
|
||||
if ($column->getFormat() !== null) {
|
||||
$style = (new Style())->setFormat($column->getFormat());
|
||||
}
|
||||
$this->styles[$i++] = $style;
|
||||
}
|
||||
|
||||
$style = new Style();
|
||||
@@ -100,12 +106,9 @@ class SpoutSpreadsheet implements SpreadsheetPackage
|
||||
}
|
||||
|
||||
$tmp = [];
|
||||
$i = 0;
|
||||
foreach ($columns as $column) {
|
||||
if ($column instanceof \DateTimeInterface) {
|
||||
$tmp[] = Cell::fromValue($column, $this->dateStyle);
|
||||
} else {
|
||||
$tmp[] = Cell::fromValue($column); // @phpstan-ignore argument.type
|
||||
}
|
||||
$tmp[] = Cell::fromValue($column, $this->styles[$i++]); // @phpstan-ignore argument.type
|
||||
}
|
||||
|
||||
$this->writer->addRow(new Row($tmp, $style));
|
||||
|
||||
@@ -207,15 +207,22 @@ class TimesheetEditForm extends AbstractType
|
||||
|
||||
/** @var \DateTime|null $date */
|
||||
$date = $event->getForm()->get('begin_date')->getData();
|
||||
/** @var \DateTime|null $time */
|
||||
$time = $event->getForm()->get('begin_time')->getData();
|
||||
|
||||
if ($date === null || $time === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// if the user did not change the time, make sure to keep the seconds
|
||||
$seconds = 0;
|
||||
if ($data->getBegin()?->format('H:i') === $time->format('H:i')) {
|
||||
$seconds = $data->getBegin()->format('s') ?? 0;
|
||||
}
|
||||
|
||||
// mutable datetime are a problem for doctrine
|
||||
$newDate = clone $date;
|
||||
$newDate->setTime($time->format('H'), $time->format('i'));
|
||||
$newDate->setTime((int) $time->format('H'), (int) $time->format('i'), (int) $seconds);
|
||||
|
||||
if ($data->getBegin() === null || $data->getBegin()->getTimestamp() !== $newDate->getTimestamp()) {
|
||||
$data->setBegin($newDate);
|
||||
@@ -251,6 +258,7 @@ class TimesheetEditForm extends AbstractType
|
||||
$timesheet = $event->getData();
|
||||
$oldEnd = $timesheet->getEnd();
|
||||
|
||||
/** @var \DateTime|null $end */
|
||||
$end = $event->getForm()->get('end_time')->getData();
|
||||
if ($end === null || $end === false) {
|
||||
$timesheet->setEnd(null);
|
||||
@@ -267,8 +275,15 @@ class TimesheetEditForm extends AbstractType
|
||||
if ($time === null) {
|
||||
throw new \Exception('Cannot work with timesheets without start time');
|
||||
}
|
||||
|
||||
// if the user did not change the time, make sure to keep the seconds
|
||||
$seconds = 0;
|
||||
if ($oldEnd !== null && $oldEnd->format('H:i') === $end->format('H:i')) {
|
||||
$seconds = $oldEnd->format('s') ?? 0;
|
||||
}
|
||||
|
||||
$newEnd = clone $time;
|
||||
$newEnd->setTime($end->format('H'), $end->format('i'));
|
||||
$newEnd->setTime((int) $end->format('H'), (int) $end->format('i'), (int) $seconds);
|
||||
|
||||
if ($newEnd < $time) {
|
||||
$newEnd->modify('+ 1 day');
|
||||
|
||||
@@ -18,11 +18,17 @@ final class InvoiceModelDefaultHydrator implements InvoiceModelHydrator
|
||||
|
||||
public function hydrate(InvoiceModel $model): array
|
||||
{
|
||||
$template = $model->getTemplate();
|
||||
if ($template === null) {
|
||||
throw new \InvalidArgumentException('InvoiceModel needs a template');
|
||||
}
|
||||
|
||||
$currency = $model->getCurrency();
|
||||
$tax = $model->getCalculator()->getTax();
|
||||
$total = $model->getCalculator()->getTotal();
|
||||
$subtotal = $model->getCalculator()->getSubtotal();
|
||||
$formatter = $model->getFormatter();
|
||||
$language = $template->getLanguage();
|
||||
|
||||
$values = [
|
||||
'invoice.due_date' => $formatter->getFormattedDateTime($model->getDueDate()),
|
||||
@@ -31,7 +37,7 @@ final class InvoiceModelDefaultHydrator implements InvoiceModelHydrator
|
||||
'invoice.date_process' => $model->getInvoiceDate()->format(self::DATE_PROCESS_FORMAT), // since 2.14
|
||||
'invoice.number' => $model->getInvoiceNumber(),
|
||||
'invoice.currency' => $currency,
|
||||
'invoice.language' => $model->getTemplate()->getLanguage(), // since 1.9
|
||||
'invoice.language' => $language, // since 1.9
|
||||
'invoice.currency_symbol' => $formatter->getCurrencySymbol($currency),
|
||||
'invoice.vat' => $model->getCalculator()->getVat(),
|
||||
'invoice.tax_hide' => $model->isHideZeroTax() && $tax === 0.00,
|
||||
@@ -47,15 +53,17 @@ final class InvoiceModelDefaultHydrator implements InvoiceModelHydrator
|
||||
'invoice.subtotal_nc' => $formatter->getFormattedMoney($subtotal, $currency, false),
|
||||
'invoice.subtotal_plain' => $subtotal,
|
||||
|
||||
'template.name' => $model->getTemplate()->getName() ?? '',
|
||||
'template.company' => $model->getTemplate()->getCompany() ?? '',
|
||||
'template.address' => $model->getTemplate()->getAddress() ?? '',
|
||||
'template.title' => $model->getTemplate()->getTitle() ?? '',
|
||||
'template.payment_terms' => $model->getTemplate()->getPaymentTerms() ?? '',
|
||||
'template.due_days' => $model->getTemplate()->getDueDays(),
|
||||
'template.vat_id' => $model->getTemplate()->getVatId() ?? '',
|
||||
'template.contact' => $model->getTemplate()->getContact() ?? '',
|
||||
'template.payment_details' => $model->getTemplate()->getPaymentDetails() ?? '',
|
||||
'template.name' => $template->getName() ?? '',
|
||||
'template.company' => $template->getCompany() ?? '',
|
||||
'template.address' => $template->getAddress() ?? '',
|
||||
'template.title' => $template->getTitle() ?? '',
|
||||
'template.payment_terms' => $template->getPaymentTerms() ?? '',
|
||||
'template.due_days' => $template->getDueDays(),
|
||||
'template.vat_id' => $template->getVatId() ?? '',
|
||||
'template.contact' => $template->getContact() ?? '',
|
||||
'template.country' => null,
|
||||
'template.country_name' => null,
|
||||
'template.payment_details' => $template->getPaymentDetails() ?? '',
|
||||
|
||||
'query.begin' => '',
|
||||
'query.begin_day' => '',
|
||||
|
||||
@@ -128,12 +128,23 @@ final class ProjectService
|
||||
// we cannot use max(number) because a varchar column returns unexpected results
|
||||
$start = $this->repository->countProject();
|
||||
$i = 0;
|
||||
$createDate = new \DateTimeImmutable();
|
||||
|
||||
do {
|
||||
$start++;
|
||||
|
||||
$numberGenerator = new NumberGenerator($format, function (string $originalFormat, string $format, int $increaseBy) use ($start): string|int {
|
||||
$numberGenerator = new NumberGenerator($format, function (string $originalFormat, string $format, int $increaseBy) use ($start, $createDate): string|int {
|
||||
return match ($format) {
|
||||
'Y' => $createDate->format('Y'),
|
||||
'y' => $createDate->format('y'),
|
||||
'M' => $createDate->format('m'),
|
||||
'm' => $createDate->format('n'),
|
||||
'D' => $createDate->format('d'),
|
||||
'd' => $createDate->format('j'),
|
||||
'YY' => (int) $createDate->format('Y') + $increaseBy,
|
||||
'yy' => (int) $createDate->format('y') + $increaseBy,
|
||||
'MM' => (int) $createDate->format('m') + $increaseBy,
|
||||
'DD' => (int) $createDate->format('d') + $increaseBy,
|
||||
'pc' => $start + $increaseBy,
|
||||
default => $originalFormat,
|
||||
};
|
||||
|
||||
@@ -48,8 +48,14 @@ final class DateTimeFactory
|
||||
return $date;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
public function getStartOfLastMonth(): DateTimeInterface
|
||||
{
|
||||
@trigger_error('The method "DateTimeFactory::getStartOfLastMonth()" will be removed soon', E_USER_DEPRECATED);
|
||||
|
||||
$date = $this->createDateTime('first day of -1 month');
|
||||
$date = $date->setTime(0, 0, 0);
|
||||
|
||||
@@ -66,9 +72,13 @@ final class DateTimeFactory
|
||||
return $this->createDateTime($date);
|
||||
}
|
||||
|
||||
return DateTime::createFromInterface($date);
|
||||
return $this->createDateTime($date->format('Y-m-d H:i:s'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
private function createDate(DateTimeInterface|string|null $date = null): \DateTimeImmutable
|
||||
{
|
||||
if ($date === null) {
|
||||
@@ -79,7 +89,7 @@ final class DateTimeFactory
|
||||
return $this->create($date);
|
||||
}
|
||||
|
||||
return \DateTimeImmutable::createFromInterface($date);
|
||||
return $this->create($date->format('Y-m-d H:i:s'));
|
||||
}
|
||||
|
||||
public function getStartOfWeek(DateTimeInterface|string|null $date = null): DateTime
|
||||
@@ -125,8 +135,14 @@ final class DateTimeFactory
|
||||
return $date;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
public function getEndOfLastMonth(): DateTimeInterface
|
||||
{
|
||||
@trigger_error('The method "DateTimeFactory::getEndOfLastMonth()" will be removed soon', E_USER_DEPRECATED);
|
||||
|
||||
$date = $this->createDateTime('last day of -1 month');
|
||||
$date = $date->setTime(23, 59, 59);
|
||||
|
||||
@@ -152,15 +168,27 @@ final class DateTimeFactory
|
||||
return new \DateTimeImmutable($datetime, $this->getTimezone());
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
public function createStartOfDay(DateTimeInterface|string|null $date = null): \DateTimeImmutable
|
||||
{
|
||||
@trigger_error('The method "DateTimeFactory::createStartOfDay()" will be removed soon', E_USER_DEPRECATED);
|
||||
|
||||
$date = $this->createDate($date);
|
||||
|
||||
return $date->modify('00:00:00');
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
public function createEndOfDay(DateTimeInterface|string|null $date = null): \DateTimeImmutable
|
||||
{
|
||||
@trigger_error('The method "DateTimeFactory::createEndOfDay()" will be removed soon', E_USER_DEPRECATED);
|
||||
|
||||
$date = $this->createDate($date);
|
||||
|
||||
return $date->modify('23:59:59');
|
||||
|
||||
@@ -97,9 +97,9 @@ final class ThemeExtension implements RuntimeExtensionInterface
|
||||
return $class;
|
||||
}
|
||||
|
||||
public function generateTitle(?string $prefix = null, string $delimiter = ' – '): string
|
||||
public function generateTitle(): string
|
||||
{
|
||||
return ($prefix ?? '') . Constants::SOFTWARE;
|
||||
return Constants::SOFTWARE;
|
||||
}
|
||||
|
||||
public function colorize(?string $color, ?string $identifier = null): string
|
||||
|
||||
Reference in New Issue
Block a user