Release 2.0.35 (#4302)
This commit is contained in:
@@ -148,7 +148,7 @@ abstract class AbstractBundleInstallerCommand extends Command
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
|
||||
protected function installAssets(SymfonyStyle $io, OutputInterface $output)
|
||||
protected function installAssets(SymfonyStyle $io, OutputInterface $output): void
|
||||
{
|
||||
$command = $this->getApplication()->find('assets:install');
|
||||
$cmdInput = new ArrayInput([]);
|
||||
@@ -160,12 +160,12 @@ abstract class AbstractBundleInstallerCommand extends Command
|
||||
$io->writeln('');
|
||||
}
|
||||
|
||||
protected function importMigrations(SymfonyStyle $io, OutputInterface $output)
|
||||
protected function importMigrations(SymfonyStyle $io, OutputInterface $output): void
|
||||
{
|
||||
$config = $this->getMigrationConfigFilename();
|
||||
|
||||
if (null === $config) {
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!file_exists($config)) {
|
||||
|
||||
@@ -56,5 +56,5 @@ abstract class AbstractRoleCommand extends Command
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
|
||||
abstract protected function executeRoleCommand(UserService $manipulator, SymfonyStyle $output, User $user, bool $super, $role);
|
||||
abstract protected function executeRoleCommand(UserService $manipulator, SymfonyStyle $output, User $user, bool $super, $role): void;
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ final class DemoteUserCommand extends AbstractRoleCommand
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function executeRoleCommand(UserService $manipulator, SymfonyStyle $output, User $user, bool $super, $role)
|
||||
protected function executeRoleCommand(UserService $manipulator, SymfonyStyle $output, User $user, bool $super, $role): void
|
||||
{
|
||||
$username = $user->getUserIdentifier();
|
||||
if ($super) {
|
||||
|
||||
@@ -46,10 +46,7 @@ final class ExportCreateCommand extends Command
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function configure()
|
||||
protected function configure(): void
|
||||
{
|
||||
$this
|
||||
->setDescription('Create exports')
|
||||
|
||||
@@ -33,7 +33,7 @@ final class PromoteUserCommand extends AbstractRoleCommand
|
||||
);
|
||||
}
|
||||
|
||||
protected function executeRoleCommand(UserService $manipulator, SymfonyStyle $output, User $user, bool $super, $role)
|
||||
protected function executeRoleCommand(UserService $manipulator, SymfonyStyle $output, User $user, bool $super, $role): void
|
||||
{
|
||||
$username = $user->getUserIdentifier();
|
||||
if ($super) {
|
||||
|
||||
@@ -106,7 +106,7 @@ final class ReloadCommand extends Command
|
||||
]
|
||||
);
|
||||
|
||||
return (int) $cacheResult;
|
||||
return $cacheResult;
|
||||
}
|
||||
|
||||
$io->success(
|
||||
@@ -116,7 +116,7 @@ final class ReloadCommand extends Command
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
|
||||
private function rebuildCaches(string $environment, SymfonyStyle $io, InputInterface $input, OutputInterface $output)
|
||||
private function rebuildCaches(string $environment, SymfonyStyle $io, InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$io->text('Rebuilding your cache, please be patient ...');
|
||||
|
||||
|
||||
@@ -32,14 +32,11 @@ final class SystemConfiguration
|
||||
|
||||
/**
|
||||
* Set an array item to a given value using "dot" notation.
|
||||
*
|
||||
* If no key is given to the method, the entire array will be replaced.
|
||||
*
|
||||
* @param string $key
|
||||
* @param mixed $value
|
||||
* @return void
|
||||
* @internal
|
||||
*/
|
||||
private function set(string $key, $value): void
|
||||
public function set(string $key, mixed $value): void
|
||||
{
|
||||
if (\array_key_exists($key, $this->settings)) {
|
||||
if (\is_bool($this->settings[$key])) {
|
||||
@@ -125,31 +122,35 @@ final class SystemConfiguration
|
||||
|
||||
// ========== Array access methods ==========
|
||||
|
||||
/**
|
||||
* @deprecated since 2.0.35
|
||||
*/
|
||||
public function offsetExists($offset): bool
|
||||
{
|
||||
return $this->has($offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated since 2.0.35
|
||||
*/
|
||||
public function offsetGet($offset): mixed
|
||||
{
|
||||
return $this->find($offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $offset
|
||||
* @param mixed $value
|
||||
* @throws \BadMethodCallException
|
||||
* @deprecated since 2.0.35
|
||||
*/
|
||||
public function offsetSet($offset, $value)
|
||||
public function offsetSet(mixed $offset, mixed $value): void
|
||||
{
|
||||
$this->set($offset, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $offset
|
||||
* @deprecated since 2.0.35
|
||||
* @throws \BadMethodCallException
|
||||
*/
|
||||
public function offsetUnset($offset)
|
||||
public function offsetUnset(mixed $offset): void
|
||||
{
|
||||
throw new \BadMethodCallException('SystemBundleConfiguration does not support offsetUnset()');
|
||||
}
|
||||
|
||||
@@ -17,11 +17,11 @@ class Constants
|
||||
/**
|
||||
* The current release version
|
||||
*/
|
||||
public const VERSION = '2.0.34';
|
||||
public const VERSION = '2.0.35';
|
||||
/**
|
||||
* The current release: major * 10000 + minor * 100 + patch
|
||||
*/
|
||||
public const VERSION_ID = 20034;
|
||||
public const VERSION_ID = 20035;
|
||||
/**
|
||||
* The software name
|
||||
*/
|
||||
|
||||
@@ -25,7 +25,7 @@ final class SamlController extends AbstractController
|
||||
}
|
||||
|
||||
#[Route(path: '/login', name: 'saml_login')]
|
||||
public function loginAction(Request $request)
|
||||
public function loginAction(Request $request): Response
|
||||
{
|
||||
if (!$this->samlConfiguration->isActivated()) {
|
||||
throw $this->createNotFoundException('SAML deactivated');
|
||||
@@ -50,11 +50,19 @@ final class SamlController extends AbstractController
|
||||
throw new \RuntimeException($error);
|
||||
}
|
||||
|
||||
$this->authFactory->create()->login($session->get('_security.main.target_path'));
|
||||
// this does set headers and exit as $stay is not set to true
|
||||
$url = $this->authFactory->create()->login($session->get('_security.main.target_path'));
|
||||
|
||||
if ($url === null) {
|
||||
throw new \RuntimeException('SAML login failed');
|
||||
}
|
||||
|
||||
// this line is not (yet) reached, as the previous call will exit
|
||||
return $this->redirect($url);
|
||||
}
|
||||
|
||||
#[Route(path: '/metadata', name: 'saml_metadata')]
|
||||
public function metadataAction()
|
||||
public function metadataAction(): Response
|
||||
{
|
||||
if (!$this->samlConfiguration->isActivated()) {
|
||||
throw $this->createNotFoundException('SAML deactivated');
|
||||
@@ -69,7 +77,7 @@ final class SamlController extends AbstractController
|
||||
}
|
||||
|
||||
#[Route(path: '/acs', name: 'saml_acs')]
|
||||
public function assertionConsumerServiceAction()
|
||||
public function assertionConsumerServiceAction(): Response
|
||||
{
|
||||
if (!$this->samlConfiguration->isActivated()) {
|
||||
throw $this->createNotFoundException('SAML deactivated');
|
||||
@@ -79,7 +87,7 @@ final class SamlController extends AbstractController
|
||||
}
|
||||
|
||||
#[Route(path: '/logout', name: 'saml_logout')]
|
||||
public function logoutAction()
|
||||
public function logoutAction(): Response
|
||||
{
|
||||
if (!$this->samlConfiguration->isActivated()) {
|
||||
throw $this->createNotFoundException('SAML deactivated');
|
||||
|
||||
@@ -387,7 +387,7 @@ final class InvoiceController extends AbstractController
|
||||
|
||||
#[Route(path: '/export', name: 'invoice_export', methods: ['GET'])]
|
||||
#[IsGranted('view_invoice')]
|
||||
public function exportAction(Request $request, EntityWithMetaFieldsExporter $exporter)
|
||||
public function exportAction(Request $request, EntityWithMetaFieldsExporter $exporter): Response
|
||||
{
|
||||
$query = new InvoiceArchiveQuery();
|
||||
$query->setCurrentUser($this->getUser());
|
||||
|
||||
@@ -46,7 +46,7 @@ final class PermissionController extends AbstractController
|
||||
|
||||
#[Route(path: '', name: 'admin_user_permissions', methods: ['GET', 'POST'])]
|
||||
#[IsGranted('role_permissions')]
|
||||
public function permissions(EventDispatcherInterface $dispatcher, CsrfTokenManagerInterface $csrfTokenManager, RoleService $roleService)
|
||||
public function permissions(EventDispatcherInterface $dispatcher, CsrfTokenManagerInterface $csrfTokenManager, RoleService $roleService): Response
|
||||
{
|
||||
$all = $this->roleRepository->findAll();
|
||||
$existing = [];
|
||||
|
||||
@@ -18,6 +18,7 @@ use App\Repository\TimesheetRepository;
|
||||
use App\Timesheet\TimesheetService;
|
||||
use App\Utils\PageSetup;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
use Symfony\Component\Security\Http\Attribute\IsGranted;
|
||||
|
||||
@@ -33,7 +34,7 @@ final class QuickEntryController extends AbstractController
|
||||
}
|
||||
|
||||
#[Route(path: '/{begin}', name: 'quick_entry', methods: ['GET', 'POST'])]
|
||||
public function quickEntry(Request $request, ?string $begin = null)
|
||||
public function quickEntry(Request $request, ?string $begin = null): Response
|
||||
{
|
||||
$factory = $this->getDateTimeFactory();
|
||||
|
||||
|
||||
@@ -49,13 +49,13 @@ final class SecurityController extends AbstractController
|
||||
}
|
||||
|
||||
#[Route(path: '/login_check', name: 'security_check', methods: ['POST'])]
|
||||
public function checkAction()
|
||||
public function checkAction(): Response
|
||||
{
|
||||
throw new \RuntimeException('You must configure the check path to be handled by the firewall using form_login in your security firewall configuration.');
|
||||
}
|
||||
|
||||
#[Route(path: '/logout', name: 'logout', methods: ['GET', 'POST'])]
|
||||
public function logoutAction()
|
||||
public function logoutAction(): Response
|
||||
{
|
||||
throw new \RuntimeException('You must activate the logout in your security firewall configuration.');
|
||||
}
|
||||
|
||||
@@ -418,7 +418,7 @@ abstract class TimesheetAbstractController extends AbstractController
|
||||
]);
|
||||
}
|
||||
|
||||
protected function multiDelete(Request $request)
|
||||
protected function multiDelete(Request $request): Response
|
||||
{
|
||||
$form = $this->getMultiUpdateActionForm();
|
||||
$form->handleRequest($request);
|
||||
@@ -446,7 +446,7 @@ abstract class TimesheetAbstractController extends AbstractController
|
||||
return $this->redirectToRoute($this->getTimesheetRoute());
|
||||
}
|
||||
|
||||
protected function prepareQuery(TimesheetQuery $query)
|
||||
protected function prepareQuery(TimesheetQuery $query): void
|
||||
{
|
||||
$query->setUser($this->getUser());
|
||||
}
|
||||
|
||||
@@ -164,7 +164,7 @@ final class TimesheetTeamController extends TimesheetAbstractController
|
||||
return $this->multiDelete($request);
|
||||
}
|
||||
|
||||
protected function prepareQuery(TimesheetQuery $query)
|
||||
protected function prepareQuery(TimesheetQuery $query): void
|
||||
{
|
||||
$query->setCurrentUser($this->getUser());
|
||||
}
|
||||
|
||||
@@ -193,7 +193,7 @@ final class UserController extends AbstractController
|
||||
|
||||
#[Route(path: '/export', name: 'user_export', methods: ['GET'])]
|
||||
#[IsGranted('view_user')]
|
||||
public function exportAction(Request $request, UserExporter $exporter)
|
||||
public function exportAction(Request $request, UserExporter $exporter): Response
|
||||
{
|
||||
$query = new UserQuery();
|
||||
$query->setCurrentUser($this->getUser());
|
||||
|
||||
@@ -105,7 +105,7 @@ final class Configuration implements ConfigurationInterface
|
||||
return $node;
|
||||
}
|
||||
|
||||
private function getProjectNode()
|
||||
private function getProjectNode(): ArrayNodeDefinition
|
||||
{
|
||||
$builder = new TreeBuilder('project');
|
||||
/** @var ArrayNodeDefinition $node */
|
||||
|
||||
@@ -52,7 +52,7 @@ abstract class AbstractMigration extends BaseAbstractMigration
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function abortIfPlatformNotSupported()
|
||||
protected function abortIfPlatformNotSupported(): void
|
||||
{
|
||||
$platform = $this->connection->getDatabasePlatform();
|
||||
if (!($platform instanceof MySQLPlatform)) {
|
||||
|
||||
@@ -21,16 +21,16 @@ final class RevenueStatisticEvent extends Event
|
||||
*/
|
||||
private array $revenue = [];
|
||||
|
||||
public function __construct(private ?\DateTime $begin, private ?\DateTime $end)
|
||||
public function __construct(private ?\DateTimeInterface $begin, private ?\DateTimeInterface $end)
|
||||
{
|
||||
}
|
||||
|
||||
public function getBegin(): ?\DateTime
|
||||
public function getBegin(): ?\DateTimeInterface
|
||||
{
|
||||
return $this->begin;
|
||||
}
|
||||
|
||||
public function getEnd(): ?\DateTime
|
||||
public function getEnd(): ?\DateTimeInterface
|
||||
{
|
||||
return $this->end;
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ final class UserPreferenceDisplayEvent extends Event
|
||||
return $this->preferences;
|
||||
}
|
||||
|
||||
public function addPreference(UserPreference $preference)
|
||||
public function addPreference(UserPreference $preference): void
|
||||
{
|
||||
$this->preferences[] = $preference;
|
||||
}
|
||||
|
||||
@@ -19,17 +19,17 @@ final class UserRevenueStatisticEvent extends Event
|
||||
{
|
||||
private RevenueStatisticEvent $event;
|
||||
|
||||
public function __construct(private User $user, ?\DateTime $begin, ?\DateTime $end)
|
||||
public function __construct(private User $user, ?\DateTimeInterface $begin, ?\DateTimeInterface $end)
|
||||
{
|
||||
$this->event = new RevenueStatisticEvent($begin, $end);
|
||||
}
|
||||
|
||||
public function getBegin(): ?\DateTime
|
||||
public function getBegin(): ?\DateTimeInterface
|
||||
{
|
||||
return $this->event->getBegin();
|
||||
}
|
||||
|
||||
public function getEnd(): ?\DateTime
|
||||
public function getEnd(): ?\DateTimeInterface
|
||||
{
|
||||
return $this->event->getEnd();
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ use Symfony\Component\Form\FormBuilderInterface;
|
||||
|
||||
abstract class AbstractRateForm extends AbstractType
|
||||
{
|
||||
protected function addFields(FormBuilderInterface $builder, ?string $currency)
|
||||
protected function addFields(FormBuilderInterface $builder, ?string $currency): void
|
||||
{
|
||||
$builder
|
||||
->add('user', UserType::class, [
|
||||
|
||||
@@ -113,8 +113,8 @@ class DateTimePickerType extends AbstractType
|
||||
'example' => (new \DateTime())->format(BaseApiController::DATE_FORMAT_PHP),
|
||||
],
|
||||
'input' => 'datetime',
|
||||
'model_timezone' => null,
|
||||
'view_timezone' => null,
|
||||
'model_timezone' => date_default_timezone_get(),
|
||||
'view_timezone' => date_default_timezone_get(),
|
||||
// Don't modify \DateTime classes by reference, we treat
|
||||
// them like immutable value objects
|
||||
'by_reference' => false,
|
||||
|
||||
@@ -17,7 +17,7 @@ final class InvoiceItemDefaultHydrator implements InvoiceItemHydrator
|
||||
{
|
||||
private InvoiceModel $model;
|
||||
|
||||
public function setInvoiceModel(InvoiceModel $model)
|
||||
public function setInvoiceModel(InvoiceModel $model): void
|
||||
{
|
||||
$this->model = $model;
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ namespace App\Invoice;
|
||||
|
||||
interface InvoiceItemHydrator
|
||||
{
|
||||
public function setInvoiceModel(InvoiceModel $model);
|
||||
public function setInvoiceModel(InvoiceModel $model): void;
|
||||
|
||||
public function hydrate(InvoiceItem $item): array;
|
||||
}
|
||||
|
||||
@@ -120,11 +120,9 @@ abstract class AbstractSpreadsheetRenderer extends AbstractRenderer
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Worksheet $worksheet
|
||||
* @param int $invoiceItemCount
|
||||
* @throws \PhpOffice\PhpSpreadsheet\Exception
|
||||
*/
|
||||
protected function addTemplateRows(Worksheet $worksheet, int $invoiceItemCount)
|
||||
protected function addTemplateRows(Worksheet $worksheet, int $invoiceItemCount): void
|
||||
{
|
||||
$startRow = null;
|
||||
$rowCounter = 0;
|
||||
|
||||
@@ -229,7 +229,7 @@ final class ServiceInvoice
|
||||
return $filename;
|
||||
}
|
||||
|
||||
public function changeInvoiceStatus(Invoice $invoice, string $status)
|
||||
public function changeInvoiceStatus(Invoice $invoice, string $status): void
|
||||
{
|
||||
switch ($status) {
|
||||
case Invoice::STATUS_NEW:
|
||||
@@ -256,7 +256,6 @@ final class ServiceInvoice
|
||||
}
|
||||
|
||||
/**
|
||||
* @param InvoiceQuery $query
|
||||
* @return ExportableItem[]
|
||||
*/
|
||||
public function getInvoiceItems(InvoiceQuery $query): array
|
||||
@@ -273,7 +272,7 @@ final class ServiceInvoice
|
||||
/**
|
||||
* @param ExportableItem[] $entries
|
||||
*/
|
||||
private function markEntriesAsExported(array $entries)
|
||||
private function markEntriesAsExported(array $entries): void
|
||||
{
|
||||
foreach ($this->getInvoiceItemRepositories() as $repository) {
|
||||
$repository->setExported($entries);
|
||||
@@ -309,9 +308,6 @@ final class ServiceInvoice
|
||||
}
|
||||
|
||||
/**
|
||||
* @param InvoiceModel $model
|
||||
* @param EventDispatcherInterface $dispatcher
|
||||
* @return Invoice
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function createInvoice(InvoiceModel $model, EventDispatcherInterface $dispatcher): Invoice
|
||||
@@ -362,7 +358,7 @@ final class ServiceInvoice
|
||||
);
|
||||
}
|
||||
|
||||
public function deleteInvoice(Invoice $invoice, EventDispatcherInterface $dispatcher)
|
||||
public function deleteInvoice(Invoice $invoice, EventDispatcherInterface $dispatcher): void
|
||||
{
|
||||
$invoiceDirectory = $this->getInvoicesDirectory();
|
||||
|
||||
@@ -377,8 +373,6 @@ final class ServiceInvoice
|
||||
}
|
||||
|
||||
/**
|
||||
* @param InvoiceQuery $query
|
||||
* @return InvoiceModel
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function createModel(InvoiceQuery $query): InvoiceModel
|
||||
@@ -485,7 +479,6 @@ final class ServiceInvoice
|
||||
}
|
||||
|
||||
/**
|
||||
* @param InvoiceQuery $query
|
||||
* @return InvoiceModel[]
|
||||
* @throws \Exception
|
||||
*/
|
||||
|
||||
@@ -72,7 +72,7 @@ class Kernel extends BaseKernel
|
||||
return $this->getProjectDir() . '/var/log';
|
||||
}
|
||||
|
||||
protected function build(ContainerBuilder $container)
|
||||
protected function build(ContainerBuilder $container): void
|
||||
{
|
||||
$container->registerForAutoconfiguration(TimesheetCalculator::class)->addTag(self::TAG_TIMESHEET_CALCULATOR);
|
||||
$container->registerForAutoconfiguration(ExportRendererInterface::class)->addTag(self::TAG_EXPORT_RENDERER);
|
||||
|
||||
@@ -42,10 +42,15 @@ class TimesheetRepository extends EntityRepository
|
||||
{
|
||||
use RepositorySearchTrait;
|
||||
|
||||
/** @deprecated since 2.0.35 */
|
||||
public const STATS_QUERY_DURATION = 'duration';
|
||||
/** @deprecated since 2.0.35 */
|
||||
public const STATS_QUERY_RATE = 'rate';
|
||||
/** @deprecated since 2.0.35 */
|
||||
public const STATS_QUERY_USER = 'users';
|
||||
/** @deprecated since 2.0.35 */
|
||||
public const STATS_QUERY_AMOUNT = 'amount';
|
||||
/** @deprecated since 2.0.35 */
|
||||
public const STATS_QUERY_ACTIVE = 'active';
|
||||
|
||||
/**
|
||||
@@ -152,42 +157,44 @@ class TimesheetRepository extends EntityRepository
|
||||
|
||||
/**
|
||||
* @param self::STATS_QUERY_* $type
|
||||
* @param DateTime|null $begin
|
||||
* @param DateTime|null $end
|
||||
* @param User|null $user
|
||||
* @return int|mixed
|
||||
* @throws \Doctrine\ORM\NonUniqueResultException
|
||||
* @deprecated since 2.0.35
|
||||
*/
|
||||
public function getStatistic(string $type, ?DateTime $begin, ?DateTime $end, ?User $user, ?bool $billable = null): mixed
|
||||
public function getStatistic(string $type, ?\DateTimeInterface $begin, ?\DateTimeInterface $end, ?User $user, ?bool $billable = null): mixed
|
||||
{
|
||||
@trigger_error('Repository method getStatistic() is deprecated, use explicit methods instead', E_USER_DEPRECATED);
|
||||
|
||||
switch ($type) {
|
||||
case self::STATS_QUERY_ACTIVE:
|
||||
return \count($this->getActiveEntries($user));
|
||||
case self::STATS_QUERY_DURATION:
|
||||
$what = 'COALESCE(SUM(t.duration), 0)';
|
||||
break;
|
||||
case self::STATS_QUERY_RATE:
|
||||
case 'active':
|
||||
return $this->countActiveEntries($user);
|
||||
case 'duration':
|
||||
return $this->getDurationForTimeRange($begin, $end, $user, $billable);
|
||||
case 'rate':
|
||||
return $this->getRevenue($begin, $end, $user);
|
||||
case self::STATS_QUERY_USER:
|
||||
$what = 'COUNT(DISTINCT(t.user))';
|
||||
break;
|
||||
case self::STATS_QUERY_AMOUNT:
|
||||
$what = 'COUNT(t.id)';
|
||||
break;
|
||||
default:
|
||||
throw new InvalidArgumentException('Invalid query type: ' . $type);
|
||||
case 'users':
|
||||
return $this->countActiveUsers($begin, $end, $billable);
|
||||
case 'amount':
|
||||
return $this->queryTimeRange('COUNT(t.id)', $begin, $end, $user, $billable);
|
||||
}
|
||||
|
||||
return $this->queryTimeRange($what, $begin, $end, $user, $billable);
|
||||
throw new InvalidArgumentException('Invalid query type: ' . $type); // @phpstan-ignore-line
|
||||
}
|
||||
|
||||
public function getDurationForTimeRange(?\DateTimeInterface $begin, ?\DateTimeInterface $end, ?User $user, ?bool $billable = null): int
|
||||
{
|
||||
$tmp = $this->queryTimeRange('COALESCE(SUM(t.duration), 0)', $begin, $end, $user, $billable);
|
||||
|
||||
if (!is_numeric($tmp)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (int) $tmp;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param DateTime|null $begin
|
||||
* @param DateTime|null $end
|
||||
* @param User|null $user
|
||||
* @return array<Revenue>
|
||||
*/
|
||||
public function getRevenue(?DateTime $begin, ?DateTime $end, ?User $user): array
|
||||
public function getRevenue(?\DateTimeInterface $begin, ?\DateTimeInterface $end, ?User $user): array
|
||||
{
|
||||
$qb = $this->getEntityManager()->createQueryBuilder();
|
||||
|
||||
@@ -198,9 +205,8 @@ class TimesheetRepository extends EntityRepository
|
||||
->leftJoin('t.project', 'p')
|
||||
->leftJoin('p.customer', 'c')
|
||||
->groupBy('c.currency')
|
||||
;
|
||||
|
||||
// TODO only billable?
|
||||
->andWhere($qb->expr()->eq('t.billable', ':billable'))
|
||||
->setParameter('billable', true);
|
||||
|
||||
if ($begin !== null) {
|
||||
$qb->andWhere($qb->expr()->between('t.begin', ':from', ':to'))
|
||||
@@ -223,14 +229,10 @@ class TimesheetRepository extends EntityRepository
|
||||
|
||||
/**
|
||||
* @param string|string[] $select
|
||||
* @param DateTime|null $begin
|
||||
* @param DateTime|null $end
|
||||
* @param User|null $user
|
||||
* @param bool|null $billable
|
||||
* @return int|mixed
|
||||
* @throws \Doctrine\ORM\NonUniqueResultException
|
||||
*/
|
||||
protected function queryTimeRange(string|array $select, ?DateTime $begin, ?DateTime $end, ?User $user, ?bool $billable = null): mixed
|
||||
private function queryTimeRange(string|array $select, ?\DateTimeInterface $begin, ?\DateTimeInterface $end, ?User $user, ?bool $billable = null): mixed
|
||||
{
|
||||
$selects = $select;
|
||||
if (!\is_array($select)) {
|
||||
@@ -349,6 +351,34 @@ class TimesheetRepository extends EntityRepository
|
||||
return $this->getHydratedResultsByQuery($qb, false);
|
||||
}
|
||||
|
||||
public function countActiveEntries(?User $user = null): int
|
||||
{
|
||||
$qb = $this->getEntityManager()->createQueryBuilder();
|
||||
|
||||
$qb->select('COUNT(t)')
|
||||
->from(Timesheet::class, 't')
|
||||
->andWhere($qb->expr()->isNull('t.end'))
|
||||
->orderBy('t.begin', 'DESC');
|
||||
|
||||
if (null !== $user) {
|
||||
$qb->andWhere('t.user = :user');
|
||||
$qb->setParameter('user', $user);
|
||||
}
|
||||
|
||||
return (int) $qb->getQuery()->getSingleScalarResult();
|
||||
}
|
||||
|
||||
public function countActiveUsers(?\DateTimeInterface $begin, ?\DateTimeInterface $end, ?bool $billable = null): int
|
||||
{
|
||||
$tmp = $this->queryTimeRange('COUNT(DISTINCT(t.user))', $begin, $end, null, $billable);
|
||||
|
||||
if (!is_numeric($tmp)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (int) $tmp;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method causes me some headaches ...
|
||||
*
|
||||
@@ -411,7 +441,7 @@ class TimesheetRepository extends EntityRepository
|
||||
return new Pagination($this->getPaginatorForQuery($query), $query);
|
||||
}
|
||||
|
||||
protected function getPaginatorForQuery(TimesheetQuery $query): PaginatorInterface
|
||||
private function getPaginatorForQuery(TimesheetQuery $query): PaginatorInterface
|
||||
{
|
||||
$qb = $this->getQueryBuilderForQuery($query);
|
||||
$qb
|
||||
|
||||
@@ -134,11 +134,9 @@ final class SamlProvider
|
||||
throw new \RuntimeException('Missing user attribute: ' . $key);
|
||||
}
|
||||
|
||||
if (!\array_key_exists(0, $attributes[$key])) {
|
||||
throw new \RuntimeException('Missing user attribute value: ' . $key);
|
||||
if (\is_array($attributes[$key]) && isset($attributes[$key][0])) {
|
||||
$results[] = $attributes[$key][0];
|
||||
}
|
||||
|
||||
$results[] = $attributes[$key][0];
|
||||
} else {
|
||||
$results[] = $part;
|
||||
}
|
||||
|
||||
@@ -21,6 +21,8 @@ use App\Repository\TimesheetRepository;
|
||||
*/
|
||||
final class FavoriteRecordService
|
||||
{
|
||||
public const MAX_FAVORITES = 5;
|
||||
|
||||
public function __construct(private TimesheetRepository $repository, private BookmarkRepository $bookmarkRepository)
|
||||
{
|
||||
}
|
||||
@@ -35,7 +37,7 @@ final class FavoriteRecordService
|
||||
/** @var array<int> $favIds */
|
||||
$favIds = $this->getBookmark($user)->getContent();
|
||||
$recentIds = [];
|
||||
if (\count($favIds) < 5) {
|
||||
if (\count($favIds) < $limit) {
|
||||
$recentIds = $this->repository->getRecentActivityIds($user, null, $limit);
|
||||
}
|
||||
/** @var array<int> $ids */
|
||||
@@ -98,7 +100,7 @@ final class FavoriteRecordService
|
||||
return;
|
||||
}
|
||||
|
||||
if (\count($ids) >= 5) {
|
||||
if (\count($ids) >= self::MAX_FAVORITES) {
|
||||
array_pop($ids); // remove the last element and make space for a new id
|
||||
}
|
||||
array_unshift($ids, $timesheet->getId());
|
||||
|
||||
@@ -9,10 +9,12 @@
|
||||
|
||||
namespace App\Widget\Type;
|
||||
|
||||
use App\Repository\TimesheetRepository;
|
||||
|
||||
abstract class AbstractActiveUsers extends AbstractSimpleStatisticChart
|
||||
abstract class AbstractActiveUsers extends AbstractWidgetType
|
||||
{
|
||||
/**
|
||||
* @param array<string, string|bool|int|null> $options
|
||||
* @return array<string, string|bool|int|null>
|
||||
*/
|
||||
public function getOptions(array $options = []): array
|
||||
{
|
||||
return array_merge([
|
||||
@@ -20,14 +22,6 @@ abstract class AbstractActiveUsers extends AbstractSimpleStatisticChart
|
||||
], parent::getOptions($options));
|
||||
}
|
||||
|
||||
public function getData(array $options = []): mixed
|
||||
{
|
||||
$this->setQueryWithUser(false);
|
||||
$this->setQuery(TimesheetRepository::STATS_QUERY_USER);
|
||||
|
||||
return parent::getData($options);
|
||||
}
|
||||
|
||||
public function getTitle(): string
|
||||
{
|
||||
return 'stats.' . lcfirst($this->getId());
|
||||
|
||||
@@ -29,6 +29,10 @@ abstract class AbstractAmountPeriod extends AbstractWidget
|
||||
return 'widget/widget-counter-money.html.twig';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string|bool|int|null> $options
|
||||
* @return array<string, string|bool|int|null>
|
||||
*/
|
||||
public function getOptions(array $options = []): array
|
||||
{
|
||||
return array_merge([
|
||||
@@ -36,19 +40,12 @@ abstract class AbstractAmountPeriod extends AbstractWidget
|
||||
], parent::getOptions($options));
|
||||
}
|
||||
|
||||
protected function getRevenue(?string $begin, ?string $end, array $options = [])
|
||||
/**
|
||||
* @param array<string, string|bool|int|null> $options
|
||||
* @return array<string, float>
|
||||
*/
|
||||
protected function getRevenue(?\DateTimeInterface $begin, ?\DateTimeInterface $end, array $options = []): array
|
||||
{
|
||||
$user = $this->getUser();
|
||||
$timezone = new \DateTimeZone($user->getTimezone());
|
||||
|
||||
if ($begin !== null) {
|
||||
$begin = new \DateTime($begin, $timezone);
|
||||
}
|
||||
|
||||
if ($end !== null) {
|
||||
$end = new \DateTime($end, $timezone);
|
||||
}
|
||||
|
||||
$data = $this->repository->getRevenue($begin, $end, null);
|
||||
|
||||
$event = new RevenueStatisticEvent($begin, $end);
|
||||
|
||||
@@ -9,10 +9,12 @@
|
||||
|
||||
namespace App\Widget\Type;
|
||||
|
||||
use App\Repository\TimesheetRepository;
|
||||
|
||||
abstract class AbstractCounterDuration extends AbstractSimpleStatisticChart
|
||||
abstract class AbstractCounterDuration extends AbstractWidgetType
|
||||
{
|
||||
/**
|
||||
* @param array<string, string|bool|int|null> $options
|
||||
* @return array<string, string|bool|int|null>
|
||||
*/
|
||||
public function getOptions(array $options = []): array
|
||||
{
|
||||
return array_merge([
|
||||
@@ -20,13 +22,6 @@ abstract class AbstractCounterDuration extends AbstractSimpleStatisticChart
|
||||
], parent::getOptions($options));
|
||||
}
|
||||
|
||||
public function getData(array $options = []): mixed
|
||||
{
|
||||
$this->setQuery(TimesheetRepository::STATS_QUERY_DURATION);
|
||||
|
||||
return parent::getData($options);
|
||||
}
|
||||
|
||||
public function getTitle(): string
|
||||
{
|
||||
return 'stats.' . lcfirst($this->getId());
|
||||
|
||||
@@ -10,34 +10,39 @@
|
||||
namespace App\Widget\Type;
|
||||
|
||||
use App\Configuration\SystemConfiguration;
|
||||
use App\Repository\TimesheetRepository;
|
||||
use App\Timesheet\DateTimeFactory;
|
||||
|
||||
abstract class AbstractCounterYear extends AbstractSimpleStatisticChart
|
||||
abstract class AbstractCounterYear extends AbstractWidgetType
|
||||
{
|
||||
private bool $isFinancialYear = false;
|
||||
|
||||
public function __construct(TimesheetRepository $repository, private SystemConfiguration $systemConfiguration)
|
||||
public function __construct(private SystemConfiguration $systemConfiguration)
|
||||
{
|
||||
parent::__construct($repository);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string|bool|int|null> $options
|
||||
*/
|
||||
public function getData(array $options = []): mixed
|
||||
{
|
||||
$this->setBegin('01 january this year 00:00:00');
|
||||
$this->setEnd('31 december this year 23:59:59');
|
||||
$begin = $this->createDate('01 january this year 00:00:00');
|
||||
$end = $this->createDate('31 december this year 23:59:59');
|
||||
|
||||
if (null !== ($financialYear = $this->systemConfiguration->getFinancialYearStart())) {
|
||||
$factory = new DateTimeFactory($this->getTimezone());
|
||||
$begin = $factory->createStartOfFinancialYear($financialYear);
|
||||
$this->setBegin($begin);
|
||||
$this->setEnd($factory->createEndOfFinancialYear($begin));
|
||||
$end = $factory->createEndOfFinancialYear($begin);
|
||||
$this->isFinancialYear = true;
|
||||
}
|
||||
|
||||
return parent::getData($options);
|
||||
return $this->getYearData($begin, $end, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string|bool|int|null> $options
|
||||
*/
|
||||
abstract protected function getYearData(\DateTimeInterface $begin, \DateTimeInterface $end, array $options = []): mixed;
|
||||
|
||||
abstract protected function getFinancialYearTitle(): string;
|
||||
|
||||
public function getTitle(): string
|
||||
|
||||
@@ -1,139 +0,0 @@
|
||||
<?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\Widget\Type;
|
||||
|
||||
use App\Repository\TimesheetRepository;
|
||||
use App\Widget\WidgetException;
|
||||
use App\Widget\WidgetInterface;
|
||||
|
||||
abstract class AbstractSimpleStatisticChart extends AbstractWidgetType
|
||||
{
|
||||
/**
|
||||
* @var TimesheetRepository::STATS_QUERY_*
|
||||
*/
|
||||
private string $query;
|
||||
/**
|
||||
* @var string|\DateTime|null
|
||||
*/
|
||||
private $begin;
|
||||
/**
|
||||
* @var string|\DateTime|null
|
||||
*/
|
||||
private $end;
|
||||
private bool $queryWithUser = false;
|
||||
|
||||
public function __construct(private TimesheetRepository $repository)
|
||||
{
|
||||
}
|
||||
|
||||
public function getWidth(): int
|
||||
{
|
||||
return WidgetInterface::WIDTH_SMALL;
|
||||
}
|
||||
|
||||
public function getHeight(): int
|
||||
{
|
||||
return WidgetInterface::HEIGHT_SMALL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TimesheetRepository::STATS_QUERY_* $query
|
||||
* @return void
|
||||
*/
|
||||
public function setQuery(string $query): void
|
||||
{
|
||||
$this->query = $query;
|
||||
}
|
||||
|
||||
public function setBegin(null|string|\DateTime $begin): self
|
||||
{
|
||||
$this->begin = $begin;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getBegin(): ?\DateTime
|
||||
{
|
||||
if ($this->begin === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if ($this->begin instanceof \DateTime) {
|
||||
return $this->begin;
|
||||
}
|
||||
|
||||
return new \DateTime($this->begin, $this->getTimezone());
|
||||
}
|
||||
|
||||
public function setEnd(null|string|\DateTime $end): self
|
||||
{
|
||||
$this->end = $end;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getEnd(): ?\DateTime
|
||||
{
|
||||
if ($this->end === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if ($this->end instanceof \DateTime) {
|
||||
return $this->end;
|
||||
}
|
||||
|
||||
return new \DateTime($this->end, $this->getTimezone());
|
||||
}
|
||||
|
||||
public function setQueryWithUser(bool $queryWithUser): self
|
||||
{
|
||||
$this->queryWithUser = $queryWithUser;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getTimezone(): \DateTimeZone
|
||||
{
|
||||
$timezone = date_default_timezone_get();
|
||||
if (null !== $this->getUser()) {
|
||||
$timezone = $this->getUser()->getTimezone();
|
||||
}
|
||||
|
||||
return new \DateTimeZone($timezone);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $options
|
||||
* @return mixed|null
|
||||
* @throws WidgetException
|
||||
*/
|
||||
public function getData(array $options = []): mixed
|
||||
{
|
||||
try {
|
||||
$user = null;
|
||||
if (true === $this->queryWithUser) {
|
||||
$user = $this->getUser();
|
||||
}
|
||||
|
||||
return $this->repository->getStatistic($this->query, $this->getBegin(), $this->getEnd(), $user);
|
||||
} catch (\Exception $ex) {
|
||||
throw new WidgetException(
|
||||
'Failed loading widget data: ' . $ex->getMessage()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public function getTemplateName(): string
|
||||
{
|
||||
$name = (new \ReflectionClass($this))->getShortName();
|
||||
|
||||
return sprintf('widget/widget-%s.html.twig', strtolower($name));
|
||||
}
|
||||
}
|
||||
@@ -34,6 +34,10 @@ abstract class AbstractUserRevenuePeriod extends AbstractWidget
|
||||
return ['view_rate_own_timesheet'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string|bool|int|null> $options
|
||||
* @return array<string, string|bool|int|null>
|
||||
*/
|
||||
public function getOptions(array $options = []): array
|
||||
{
|
||||
return array_merge([
|
||||
@@ -41,18 +45,13 @@ abstract class AbstractUserRevenuePeriod extends AbstractWidget
|
||||
], parent::getOptions($options));
|
||||
}
|
||||
|
||||
protected function getRevenue(?string $begin, ?string $end, array $options = [])
|
||||
/**
|
||||
* @param array<string, string|bool|int|null> $options
|
||||
* @return array<string, float>
|
||||
*/
|
||||
protected function getRevenue(?\DateTimeInterface $begin, ?\DateTimeInterface $end, array $options = []): array
|
||||
{
|
||||
$user = $this->getUser();
|
||||
$timezone = new \DateTimeZone($user->getTimezone());
|
||||
|
||||
if ($begin !== null) {
|
||||
$begin = new \DateTime($begin, $timezone);
|
||||
}
|
||||
|
||||
if ($end !== null) {
|
||||
$end = new \DateTime($end, $timezone);
|
||||
}
|
||||
|
||||
$data = $this->repository->getRevenue($begin, $end, $user);
|
||||
|
||||
|
||||
@@ -67,6 +67,10 @@ abstract class AbstractWidget implements WidgetInterface
|
||||
$this->options[$name] = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string|bool|int|null> $options
|
||||
* @return array<string, string|bool|int|null>
|
||||
*/
|
||||
public function getOptions(array $options = []): array
|
||||
{
|
||||
return array_merge($this->options, $options);
|
||||
@@ -76,4 +80,56 @@ abstract class AbstractWidget implements WidgetInterface
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
protected function createDate(string $date): \DateTime
|
||||
{
|
||||
return new \DateTime($date, $this->getTimezone());
|
||||
}
|
||||
|
||||
protected function createMonthStartDate(): \DateTime
|
||||
{
|
||||
return $this->createDate('first day of this month 00:00:00');
|
||||
}
|
||||
|
||||
protected function createMonthEndDate(): \DateTime
|
||||
{
|
||||
return $this->createDate('last day of this month 23:59:59');
|
||||
}
|
||||
|
||||
protected function createWeekStartDate(): \DateTime
|
||||
{
|
||||
return $this->createDate('monday this week 00:00:00');
|
||||
}
|
||||
|
||||
protected function createWeekEndDate(): \DateTime
|
||||
{
|
||||
return $this->createDate('sunday this week 23:59:59');
|
||||
}
|
||||
|
||||
protected function createTodayStartDate(): \DateTime
|
||||
{
|
||||
return $this->createDate('00:00:00');
|
||||
}
|
||||
|
||||
protected function createTodayEndDate(): \DateTime
|
||||
{
|
||||
return $this->createDate('23:59:59');
|
||||
}
|
||||
|
||||
public function getTimezone(): \DateTimeZone
|
||||
{
|
||||
$timezone = date_default_timezone_get();
|
||||
if (null !== $this->user) {
|
||||
$timezone = $this->user->getTimezone();
|
||||
}
|
||||
|
||||
return new \DateTimeZone($timezone);
|
||||
}
|
||||
|
||||
public function getTemplateName(): string
|
||||
{
|
||||
$name = (new \ReflectionClass($this))->getShortName();
|
||||
|
||||
return sprintf('widget/widget-%s.html.twig', strtolower($name));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,48 +9,18 @@
|
||||
|
||||
namespace App\Widget\Type;
|
||||
|
||||
use App\Widget\WidgetInterface;
|
||||
|
||||
abstract class AbstractWidgetType extends AbstractWidget
|
||||
{
|
||||
private ?string $id = null;
|
||||
private string $title = '';
|
||||
private int $height = WidgetInterface::HEIGHT_SMALL;
|
||||
private int $width = WidgetInterface::WIDTH_SMALL;
|
||||
/**
|
||||
* @var array<string>
|
||||
*/
|
||||
private array $permissions = [];
|
||||
|
||||
public function getHeight(): int
|
||||
{
|
||||
return $this->height;
|
||||
}
|
||||
|
||||
public function setHeight(int $height): AbstractWidgetType
|
||||
{
|
||||
$this->height = $height;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getWidth(): int
|
||||
{
|
||||
return $this->width;
|
||||
}
|
||||
|
||||
public function setWidth(int $width): AbstractWidgetType
|
||||
{
|
||||
$this->width = $width;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setId(string $id): self
|
||||
public function setId(string $id): void
|
||||
{
|
||||
$this->id = $id;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getId(): string
|
||||
@@ -62,11 +32,9 @@ abstract class AbstractWidgetType extends AbstractWidget
|
||||
return (new \ReflectionClass($this))->getShortName();
|
||||
}
|
||||
|
||||
public function setTitle(string $title): self
|
||||
public function setTitle(string $title): void
|
||||
{
|
||||
$this->title = $title;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getTitle(): string
|
||||
@@ -74,13 +42,11 @@ abstract class AbstractWidgetType extends AbstractWidget
|
||||
return $this->title;
|
||||
}
|
||||
|
||||
public function setOptions(array $options): self
|
||||
public function setOptions(array $options): void
|
||||
{
|
||||
foreach ($options as $key => $value) {
|
||||
$this->setOption($key, $value);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getPermissions(): array
|
||||
@@ -88,10 +54,8 @@ abstract class AbstractWidgetType extends AbstractWidget
|
||||
return $this->permissions;
|
||||
}
|
||||
|
||||
public function setPermissions(array $permissions): AbstractWidgetType
|
||||
public function setPermissions(array $permissions): void
|
||||
{
|
||||
$this->permissions = $permissions;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,10 +10,19 @@
|
||||
namespace App\Widget\Type;
|
||||
|
||||
use App\Repository\TimesheetRepository;
|
||||
use App\Widget\WidgetException;
|
||||
use App\Widget\WidgetInterface;
|
||||
|
||||
final class ActiveTimesheets extends AbstractSimpleStatisticChart
|
||||
final class ActiveTimesheets extends AbstractWidgetType
|
||||
{
|
||||
public function __construct(private TimesheetRepository $repository)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string|bool|int|null> $options
|
||||
* @return array<string, string|bool|int|null>
|
||||
*/
|
||||
public function getOptions(array $options = []): array
|
||||
{
|
||||
return array_merge(['color' => WidgetInterface::COLOR_TOTAL, 'icon' => 'duration'], parent::getOptions($options));
|
||||
@@ -34,12 +43,18 @@ final class ActiveTimesheets extends AbstractSimpleStatisticChart
|
||||
return 'stats.activeRecordings';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string|bool|int|null> $options
|
||||
*/
|
||||
public function getData(array $options = []): mixed
|
||||
{
|
||||
$this->setQueryWithUser(false);
|
||||
$this->setQuery(TimesheetRepository::STATS_QUERY_ACTIVE);
|
||||
|
||||
return parent::getData($options);
|
||||
try {
|
||||
return $this->repository->countActiveEntries();
|
||||
} catch (\Exception $ex) {
|
||||
throw new WidgetException(
|
||||
'Failed loading widget data: ' . $ex->getMessage()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public function getTemplateName(): string
|
||||
|
||||
@@ -9,10 +9,20 @@
|
||||
|
||||
namespace App\Widget\Type;
|
||||
|
||||
use App\Repository\TimesheetRepository;
|
||||
use App\Widget\WidgetException;
|
||||
use App\Widget\WidgetInterface;
|
||||
|
||||
final class ActiveUsersMonth extends AbstractActiveUsers
|
||||
{
|
||||
public function __construct(private TimesheetRepository $repository)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string|bool|int|null> $options
|
||||
* @return array<string, string|bool|int|null>
|
||||
*/
|
||||
public function getOptions(array $options = []): array
|
||||
{
|
||||
return array_merge(['color' => WidgetInterface::COLOR_MONTH], parent::getOptions($options));
|
||||
@@ -23,11 +33,17 @@ final class ActiveUsersMonth extends AbstractActiveUsers
|
||||
return 'activeUsersMonth';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string|bool|int|null> $options
|
||||
*/
|
||||
public function getData(array $options = []): mixed
|
||||
{
|
||||
$this->setBegin('first day of this month 00:00:00');
|
||||
$this->setEnd('last day of this month 23:59:59');
|
||||
|
||||
return parent::getData($options);
|
||||
try {
|
||||
return $this->repository->countActiveUsers($this->createMonthStartDate(), $this->createMonthEndDate(), null);
|
||||
} catch (\Exception $ex) {
|
||||
throw new WidgetException(
|
||||
'Failed loading widget data: ' . $ex->getMessage()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,10 +9,20 @@
|
||||
|
||||
namespace App\Widget\Type;
|
||||
|
||||
use App\Repository\TimesheetRepository;
|
||||
use App\Widget\WidgetException;
|
||||
use App\Widget\WidgetInterface;
|
||||
|
||||
final class ActiveUsersToday extends AbstractActiveUsers
|
||||
{
|
||||
public function __construct(private TimesheetRepository $repository)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string|bool|int|null> $options
|
||||
* @return array<string, string|bool|int|null>
|
||||
*/
|
||||
public function getOptions(array $options = []): array
|
||||
{
|
||||
return array_merge(['color' => WidgetInterface::COLOR_TODAY], parent::getOptions($options));
|
||||
@@ -23,11 +33,17 @@ final class ActiveUsersToday extends AbstractActiveUsers
|
||||
return 'activeUsersToday';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string|bool|int|null> $options
|
||||
*/
|
||||
public function getData(array $options = []): mixed
|
||||
{
|
||||
$this->setBegin('00:00:00');
|
||||
$this->setEnd('23:59:59');
|
||||
|
||||
return parent::getData($options);
|
||||
try {
|
||||
return $this->repository->countActiveUsers($this->createTodayStartDate(), $this->createTodayEndDate(), null);
|
||||
} catch (\Exception $ex) {
|
||||
throw new WidgetException(
|
||||
'Failed loading widget data: ' . $ex->getMessage()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,10 +9,20 @@
|
||||
|
||||
namespace App\Widget\Type;
|
||||
|
||||
use App\Repository\TimesheetRepository;
|
||||
use App\Widget\WidgetException;
|
||||
use App\Widget\WidgetInterface;
|
||||
|
||||
final class ActiveUsersTotal extends AbstractActiveUsers
|
||||
{
|
||||
public function __construct(private TimesheetRepository $repository)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string|bool|int|null> $options
|
||||
* @return array<string, string|bool|int|null>
|
||||
*/
|
||||
public function getOptions(array $options = []): array
|
||||
{
|
||||
return array_merge(['color' => WidgetInterface::COLOR_TOTAL], parent::getOptions($options));
|
||||
@@ -23,8 +33,17 @@ final class ActiveUsersTotal extends AbstractActiveUsers
|
||||
return 'activeUsersTotal';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string|bool|int|null> $options
|
||||
*/
|
||||
public function getData(array $options = []): mixed
|
||||
{
|
||||
return parent::getData($options);
|
||||
try {
|
||||
return $this->repository->countActiveUsers(null, null, null);
|
||||
} catch (\Exception $ex) {
|
||||
throw new WidgetException(
|
||||
'Failed loading widget data: ' . $ex->getMessage()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,10 +9,20 @@
|
||||
|
||||
namespace App\Widget\Type;
|
||||
|
||||
use App\Repository\TimesheetRepository;
|
||||
use App\Widget\WidgetException;
|
||||
use App\Widget\WidgetInterface;
|
||||
|
||||
final class ActiveUsersWeek extends AbstractActiveUsers
|
||||
{
|
||||
public function __construct(private TimesheetRepository $repository)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string|bool|int|null> $options
|
||||
* @return array<string, string|bool|int|null>
|
||||
*/
|
||||
public function getOptions(array $options = []): array
|
||||
{
|
||||
return array_merge(['color' => WidgetInterface::COLOR_WEEK], parent::getOptions($options));
|
||||
@@ -23,11 +33,17 @@ final class ActiveUsersWeek extends AbstractActiveUsers
|
||||
return 'activeUsersWeek';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string|bool|int|null> $options
|
||||
*/
|
||||
public function getData(array $options = []): mixed
|
||||
{
|
||||
$this->setBegin('monday this week 00:00:00');
|
||||
$this->setEnd('sunday this week 23:59:59');
|
||||
|
||||
return parent::getData($options);
|
||||
try {
|
||||
return $this->repository->countActiveUsers($this->createWeekStartDate(), $this->createWeekEndDate(), null);
|
||||
} catch (\Exception $ex) {
|
||||
throw new WidgetException(
|
||||
'Failed loading widget data: ' . $ex->getMessage()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,11 +9,22 @@
|
||||
|
||||
namespace App\Widget\Type;
|
||||
|
||||
use App\Configuration\SystemConfiguration;
|
||||
use App\Repository\TimesheetRepository;
|
||||
use App\Widget\WidgetException;
|
||||
use App\Widget\WidgetInterface;
|
||||
|
||||
final class ActiveUsersYear extends AbstractCounterYear
|
||||
{
|
||||
public function __construct(private TimesheetRepository $repository, SystemConfiguration $systemConfiguration)
|
||||
{
|
||||
parent::__construct($systemConfiguration);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string|bool|int|null> $options
|
||||
* @return array<string, string|bool|int|null>
|
||||
*/
|
||||
public function getOptions(array $options = []): array
|
||||
{
|
||||
return array_merge([
|
||||
@@ -22,12 +33,18 @@ final class ActiveUsersYear extends AbstractCounterYear
|
||||
], parent::getOptions($options));
|
||||
}
|
||||
|
||||
public function getData(array $options = []): mixed
|
||||
/**
|
||||
* @param array<string, string|bool|int|null> $options
|
||||
*/
|
||||
protected function getYearData(\DateTimeInterface $begin, \DateTimeInterface $end, array $options = []): mixed
|
||||
{
|
||||
$this->setQuery(TimesheetRepository::STATS_QUERY_USER);
|
||||
$this->setQueryWithUser(false);
|
||||
|
||||
return parent::getData($options);
|
||||
try {
|
||||
return $this->repository->countActiveUsers($begin, $end, null);
|
||||
} catch (\Exception $ex) {
|
||||
throw new WidgetException(
|
||||
'Failed loading widget data: ' . $ex->getMessage()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
protected function getFinancialYearTitle(): string
|
||||
|
||||
@@ -13,6 +13,10 @@ use App\Widget\WidgetInterface;
|
||||
|
||||
final class AmountMonth extends AbstractAmountPeriod
|
||||
{
|
||||
/**
|
||||
* @param array<string, string|bool|int|null> $options
|
||||
* @return array<string, string|bool|int|null>
|
||||
*/
|
||||
public function getOptions(array $options = []): array
|
||||
{
|
||||
return array_merge(['color' => WidgetInterface::COLOR_MONTH], parent::getOptions($options));
|
||||
@@ -23,9 +27,12 @@ final class AmountMonth extends AbstractAmountPeriod
|
||||
return 'AmountMonth';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string|bool|int|null> $options
|
||||
*/
|
||||
public function getData(array $options = []): mixed
|
||||
{
|
||||
return $this->getRevenue('first day of this month 00:00:00', 'last day of this month 23:59:59', $options);
|
||||
return $this->getRevenue($this->createMonthStartDate(), $this->createMonthEndDate(), $options);
|
||||
}
|
||||
|
||||
public function getPermissions(): array
|
||||
|
||||
@@ -13,6 +13,10 @@ use App\Widget\WidgetInterface;
|
||||
|
||||
final class AmountToday extends AbstractAmountPeriod
|
||||
{
|
||||
/**
|
||||
* @param array<string, string|bool|int|null> $options
|
||||
* @return array<string, string|bool|int|null>
|
||||
*/
|
||||
public function getOptions(array $options = []): array
|
||||
{
|
||||
return array_merge(['color' => WidgetInterface::COLOR_TODAY], parent::getOptions($options));
|
||||
@@ -23,9 +27,12 @@ final class AmountToday extends AbstractAmountPeriod
|
||||
return 'AmountToday';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string|bool|int|null> $options
|
||||
*/
|
||||
public function getData(array $options = []): mixed
|
||||
{
|
||||
return $this->getRevenue('00:00:00', '23:59:59', $options);
|
||||
return $this->getRevenue($this->createTodayStartDate(), $this->createTodayEndDate(), $options);
|
||||
}
|
||||
|
||||
public function getPermissions(): array
|
||||
|
||||
@@ -13,6 +13,10 @@ use App\Widget\WidgetInterface;
|
||||
|
||||
final class AmountTotal extends AbstractAmountPeriod
|
||||
{
|
||||
/**
|
||||
* @param array<string, string|bool|int|null> $options
|
||||
* @return array<string, string|bool|int|null>
|
||||
*/
|
||||
public function getOptions(array $options = []): array
|
||||
{
|
||||
return array_merge(['color' => WidgetInterface::COLOR_TOTAL], parent::getOptions($options));
|
||||
@@ -28,6 +32,9 @@ final class AmountTotal extends AbstractAmountPeriod
|
||||
return ['view_all_data'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string|bool|int|null> $options
|
||||
*/
|
||||
public function getData(array $options = []): mixed
|
||||
{
|
||||
return $this->getRevenue(null, null, $options);
|
||||
|
||||
@@ -13,6 +13,10 @@ use App\Widget\WidgetInterface;
|
||||
|
||||
final class AmountWeek extends AbstractAmountPeriod
|
||||
{
|
||||
/**
|
||||
* @param array<string, string|bool|int|null> $options
|
||||
* @return array<string, string|bool|int|null>
|
||||
*/
|
||||
public function getOptions(array $options = []): array
|
||||
{
|
||||
return array_merge(['color' => WidgetInterface::COLOR_WEEK], parent::getOptions($options));
|
||||
@@ -23,9 +27,12 @@ final class AmountWeek extends AbstractAmountPeriod
|
||||
return 'AmountWeek';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string|bool|int|null> $options
|
||||
*/
|
||||
public function getData(array $options = []): mixed
|
||||
{
|
||||
return $this->getRevenue('monday this week 00:00:00', 'sunday this week 23:59:59', $options);
|
||||
return $this->getRevenue($this->createWeekStartDate(), $this->createWeekEndDate(), $options);
|
||||
}
|
||||
|
||||
public function getPermissions(): array
|
||||
|
||||
@@ -13,16 +13,21 @@ use App\Configuration\SystemConfiguration;
|
||||
use App\Event\RevenueStatisticEvent;
|
||||
use App\Model\Revenue;
|
||||
use App\Repository\TimesheetRepository;
|
||||
use App\Widget\WidgetException;
|
||||
use App\Widget\WidgetInterface;
|
||||
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
|
||||
|
||||
final class AmountYear extends AbstractCounterYear
|
||||
{
|
||||
public function __construct(TimesheetRepository $repository, SystemConfiguration $systemConfiguration, private EventDispatcherInterface $dispatcher)
|
||||
public function __construct(private TimesheetRepository $repository, SystemConfiguration $systemConfiguration, private EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
parent::__construct($repository, $systemConfiguration);
|
||||
parent::__construct($systemConfiguration);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string|bool|int|null> $options
|
||||
* @return array<string, string|bool|int|null>
|
||||
*/
|
||||
public function getOptions(array $options = []): array
|
||||
{
|
||||
return array_merge([
|
||||
@@ -31,21 +36,27 @@ final class AmountYear extends AbstractCounterYear
|
||||
], parent::getOptions($options));
|
||||
}
|
||||
|
||||
public function getData(array $options = []): mixed
|
||||
/**
|
||||
* @param array<string, string|bool|int|null> $options
|
||||
*/
|
||||
protected function getYearData(\DateTimeInterface $begin, \DateTimeInterface $end, array $options = []): mixed
|
||||
{
|
||||
$this->setQuery(TimesheetRepository::STATS_QUERY_RATE);
|
||||
$this->setQueryWithUser(false);
|
||||
try {
|
||||
/** @var array<Revenue> $data */
|
||||
$data = $this->repository->getRevenue($begin, $end, null);
|
||||
|
||||
/** @var array<Revenue> $data */
|
||||
$data = parent::getData($options);
|
||||
$event = new RevenueStatisticEvent($begin, $end);
|
||||
foreach ($data as $row) {
|
||||
$event->addRevenue($row->getCurrency(), $row->getAmount());
|
||||
}
|
||||
$this->dispatcher->dispatch($event);
|
||||
|
||||
$event = new RevenueStatisticEvent($this->getBegin(), $this->getEnd());
|
||||
foreach ($data as $row) {
|
||||
$event->addRevenue($row->getCurrency(), $row->getAmount());
|
||||
return $event->getRevenue();
|
||||
} catch (\Exception $ex) {
|
||||
throw new WidgetException(
|
||||
'Failed loading widget data: ' . $ex->getMessage()
|
||||
);
|
||||
}
|
||||
$this->dispatcher->dispatch($event);
|
||||
|
||||
return $event->getRevenue();
|
||||
}
|
||||
|
||||
public function getId(): string
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
<?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\Widget\Type;
|
||||
|
||||
final class Counter extends AbstractSimpleStatisticChart
|
||||
{
|
||||
public function getTemplateName(): string
|
||||
{
|
||||
return 'widget/widget-counter.html.twig';
|
||||
}
|
||||
}
|
||||
@@ -45,6 +45,10 @@ final class DailyWorkingTimeChart extends AbstractWidget
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string|bool|int|null> $options
|
||||
* @return array<string, string|bool|int|null>
|
||||
*/
|
||||
public function getOptions(array $options = []): array
|
||||
{
|
||||
return array_merge([
|
||||
@@ -56,30 +60,30 @@ final class DailyWorkingTimeChart extends AbstractWidget
|
||||
], parent::getOptions($options));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string|bool|int|null> $options
|
||||
*/
|
||||
public function getData(array $options = []): mixed
|
||||
{
|
||||
$user = $this->getUser();
|
||||
|
||||
$dateTimeFactory = DateTimeFactory::createByUser($user);
|
||||
|
||||
if ($options['begin'] === null) {
|
||||
$options['begin'] = $dateTimeFactory->getStartOfWeek();
|
||||
$begin = $options['begin'];
|
||||
if (!($begin instanceof \DateTimeInterface)) {
|
||||
if (\is_string($begin)) {
|
||||
$begin = new DateTime($begin, new \DateTimeZone($user->getTimezone()));
|
||||
} else {
|
||||
$begin = $dateTimeFactory->getStartOfWeek();
|
||||
}
|
||||
}
|
||||
|
||||
if ($options['begin'] instanceof \DateTimeInterface) {
|
||||
$begin = $options['begin'];
|
||||
} else {
|
||||
$begin = new DateTime($options['begin'], new \DateTimeZone($user->getTimezone()));
|
||||
}
|
||||
|
||||
if ($options['end'] === null) {
|
||||
$options['end'] = $dateTimeFactory->getEndOfWeek($begin);
|
||||
}
|
||||
|
||||
if ($options['end'] instanceof \DateTimeInterface) {
|
||||
$end = $options['end'];
|
||||
} else {
|
||||
$end = new DateTime($options['end'], new \DateTimeZone($user->getTimezone()));
|
||||
$end = $options['end'];
|
||||
if (!($end instanceof \DateTimeInterface)) {
|
||||
if (\is_string($end)) {
|
||||
$end = new DateTime($end, new \DateTimeZone($user->getTimezone()));
|
||||
} else {
|
||||
$end = $dateTimeFactory->getEndOfWeek($begin);
|
||||
}
|
||||
}
|
||||
|
||||
$activities = [];
|
||||
|
||||
@@ -9,10 +9,20 @@
|
||||
|
||||
namespace App\Widget\Type;
|
||||
|
||||
use App\Repository\TimesheetRepository;
|
||||
use App\Widget\WidgetException;
|
||||
use App\Widget\WidgetInterface;
|
||||
|
||||
final class DurationMonth extends AbstractCounterDuration
|
||||
{
|
||||
public function __construct(private TimesheetRepository $repository)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string|bool|int|null> $options
|
||||
* @return array<string, string|bool|int|null>
|
||||
*/
|
||||
public function getOptions(array $options = []): array
|
||||
{
|
||||
return array_merge(['color' => WidgetInterface::COLOR_MONTH], parent::getOptions($options));
|
||||
@@ -33,12 +43,17 @@ final class DurationMonth extends AbstractCounterDuration
|
||||
return 'stats.durationMonth';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string|bool|int|null> $options
|
||||
*/
|
||||
public function getData(array $options = []): mixed
|
||||
{
|
||||
$this->setQueryWithUser(false);
|
||||
$this->setBegin('first day of this month 00:00:00');
|
||||
$this->setEnd('last day of this month 23:59:59');
|
||||
|
||||
return parent::getData($options);
|
||||
try {
|
||||
return $this->repository->getDurationForTimeRange($this->createMonthStartDate(), $this->createMonthEndDate(), null);
|
||||
} catch (\Exception $ex) {
|
||||
throw new WidgetException(
|
||||
'Failed loading widget data: ' . $ex->getMessage()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,10 +9,20 @@
|
||||
|
||||
namespace App\Widget\Type;
|
||||
|
||||
use App\Repository\TimesheetRepository;
|
||||
use App\Widget\WidgetException;
|
||||
use App\Widget\WidgetInterface;
|
||||
|
||||
final class DurationToday extends AbstractCounterDuration
|
||||
{
|
||||
public function __construct(private TimesheetRepository $repository)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string|bool|int|null> $options
|
||||
* @return array<string, string|bool|int|null>
|
||||
*/
|
||||
public function getOptions(array $options = []): array
|
||||
{
|
||||
return array_merge(['color' => WidgetInterface::COLOR_TODAY], parent::getOptions($options));
|
||||
@@ -33,12 +43,17 @@ final class DurationToday extends AbstractCounterDuration
|
||||
return 'stats.durationToday';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string|bool|int|null> $options
|
||||
*/
|
||||
public function getData(array $options = []): mixed
|
||||
{
|
||||
$this->setQueryWithUser(false);
|
||||
$this->setBegin('00:00:00');
|
||||
$this->setEnd('23:59:59');
|
||||
|
||||
return parent::getData($options);
|
||||
try {
|
||||
return $this->repository->getDurationForTimeRange($this->createTodayStartDate(), $this->createTodayEndDate(), null);
|
||||
} catch (\Exception $ex) {
|
||||
throw new WidgetException(
|
||||
'Failed loading widget data: ' . $ex->getMessage()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,10 +9,20 @@
|
||||
|
||||
namespace App\Widget\Type;
|
||||
|
||||
use App\Repository\TimesheetRepository;
|
||||
use App\Widget\WidgetException;
|
||||
use App\Widget\WidgetInterface;
|
||||
|
||||
final class DurationTotal extends AbstractCounterDuration
|
||||
{
|
||||
public function __construct(private TimesheetRepository $repository)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string|bool|int|null> $options
|
||||
* @return array<string, string|bool|int|null>
|
||||
*/
|
||||
public function getOptions(array $options = []): array
|
||||
{
|
||||
return array_merge(['color' => WidgetInterface::COLOR_TOTAL], parent::getOptions($options));
|
||||
@@ -33,10 +43,17 @@ final class DurationTotal extends AbstractCounterDuration
|
||||
return 'stats.durationTotal';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string|bool|int|null> $options
|
||||
*/
|
||||
public function getData(array $options = []): mixed
|
||||
{
|
||||
$this->setQueryWithUser(false);
|
||||
|
||||
return parent::getData($options);
|
||||
try {
|
||||
return $this->repository->getDurationForTimeRange(null, null, null);
|
||||
} catch (\Exception $ex) {
|
||||
throw new WidgetException(
|
||||
'Failed loading widget data: ' . $ex->getMessage()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,10 +9,20 @@
|
||||
|
||||
namespace App\Widget\Type;
|
||||
|
||||
use App\Repository\TimesheetRepository;
|
||||
use App\Widget\WidgetException;
|
||||
use App\Widget\WidgetInterface;
|
||||
|
||||
final class DurationWeek extends AbstractCounterDuration
|
||||
{
|
||||
public function __construct(private TimesheetRepository $repository)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string|bool|int|null> $options
|
||||
* @return array<string, string|bool|int|null>
|
||||
*/
|
||||
public function getOptions(array $options = []): array
|
||||
{
|
||||
return array_merge(['color' => WidgetInterface::COLOR_WEEK], parent::getOptions($options));
|
||||
@@ -33,12 +43,17 @@ final class DurationWeek extends AbstractCounterDuration
|
||||
return 'stats.durationWeek';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string|bool|int|null> $options
|
||||
*/
|
||||
public function getData(array $options = []): mixed
|
||||
{
|
||||
$this->setQueryWithUser(false);
|
||||
$this->setBegin('monday this week 00:00:00');
|
||||
$this->setEnd('sunday this week 23:59:59');
|
||||
|
||||
return parent::getData($options);
|
||||
try {
|
||||
return $this->repository->getDurationForTimeRange($this->createWeekStartDate(), $this->createWeekEndDate(), null);
|
||||
} catch (\Exception $ex) {
|
||||
throw new WidgetException(
|
||||
'Failed loading widget data: ' . $ex->getMessage()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,11 +9,22 @@
|
||||
|
||||
namespace App\Widget\Type;
|
||||
|
||||
use App\Configuration\SystemConfiguration;
|
||||
use App\Repository\TimesheetRepository;
|
||||
use App\Widget\WidgetException;
|
||||
use App\Widget\WidgetInterface;
|
||||
|
||||
final class DurationYear extends AbstractCounterYear
|
||||
{
|
||||
public function __construct(private TimesheetRepository $repository, SystemConfiguration $systemConfiguration)
|
||||
{
|
||||
parent::__construct($systemConfiguration);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string|bool|int|null> $options
|
||||
* @return array<string, string|bool|int|null>
|
||||
*/
|
||||
public function getOptions(array $options = []): array
|
||||
{
|
||||
return array_merge([
|
||||
@@ -22,12 +33,18 @@ final class DurationYear extends AbstractCounterYear
|
||||
], parent::getOptions($options));
|
||||
}
|
||||
|
||||
public function getData(array $options = []): mixed
|
||||
/**
|
||||
* @param array<string, string|bool|int|null> $options
|
||||
*/
|
||||
protected function getYearData(\DateTimeInterface $begin, \DateTimeInterface $end, array $options = []): mixed
|
||||
{
|
||||
$this->setQuery(TimesheetRepository::STATS_QUERY_DURATION);
|
||||
$this->setQueryWithUser(false);
|
||||
|
||||
return parent::getData($options);
|
||||
try {
|
||||
return $this->repository->getDurationForTimeRange($begin, $end, null);
|
||||
} catch (\Exception $ex) {
|
||||
throw new WidgetException(
|
||||
'Failed loading widget data: ' . $ex->getMessage()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public function getPermissions(): array
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
<?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\Widget\Type;
|
||||
|
||||
class More extends AbstractWidgetType
|
||||
{
|
||||
private mixed $data = null;
|
||||
|
||||
public function setData($data): self
|
||||
{
|
||||
$this->data = $data;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $options
|
||||
* @return mixed|null
|
||||
*/
|
||||
public function getData(array $options = []): mixed
|
||||
{
|
||||
return $this->data;
|
||||
}
|
||||
|
||||
public function getTemplateName(): string
|
||||
{
|
||||
return 'widget/widget-more.html.twig';
|
||||
}
|
||||
}
|
||||
@@ -12,6 +12,7 @@ namespace App\Widget\Type;
|
||||
use App\Configuration\SystemConfiguration;
|
||||
use App\Repository\TimesheetRepository;
|
||||
use App\Timesheet\DateTimeFactory;
|
||||
use App\Widget\WidgetException;
|
||||
use App\Widget\WidgetInterface;
|
||||
use DateTime;
|
||||
|
||||
@@ -46,6 +47,10 @@ final class PaginatedWorkingTimeChart extends AbstractWidget
|
||||
return 'widget/widget-paginatedworkingtimechart.html.twig';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string|bool|int|null> $options
|
||||
* @return array<string, string|bool|int|null>
|
||||
*/
|
||||
public function getOptions(array $options = []): array
|
||||
{
|
||||
$options = parent::getOptions($options);
|
||||
@@ -81,6 +86,9 @@ final class PaginatedWorkingTimeChart extends AbstractWidget
|
||||
return $lastWeekInYear->format('W') === '53' ? 53 : 52;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string|bool|int|null> $options
|
||||
*/
|
||||
public function getData(array $options = []): mixed
|
||||
{
|
||||
$user = $this->getUser();
|
||||
@@ -88,7 +96,18 @@ final class PaginatedWorkingTimeChart extends AbstractWidget
|
||||
$dateTimeFactory = DateTimeFactory::createByUser($user);
|
||||
|
||||
$year = $options['year'];
|
||||
if (\is_string($year)) {
|
||||
$year = (int) $year;
|
||||
} elseif (!\is_int($year)) {
|
||||
throw new WidgetException('Invalid year given');
|
||||
}
|
||||
|
||||
$week = $options['week'];
|
||||
if (\is_string($week)) {
|
||||
$week = (int) $week;
|
||||
} elseif (!\is_int($week)) {
|
||||
throw new WidgetException('Invalid week given');
|
||||
}
|
||||
|
||||
$weekBegin = ($dateTimeFactory->createDateTime())->setISODate($year, $week, 1)->setTime(0, 0, 0);
|
||||
|
||||
@@ -99,7 +118,7 @@ final class PaginatedWorkingTimeChart extends AbstractWidget
|
||||
$lastWeekInLastYear = $this->getLastWeekInYear($year - 1);
|
||||
|
||||
$thisMonth = clone $weekBegin;
|
||||
if ((int) $week === 1) {
|
||||
if ($week === 1) {
|
||||
$thisMonth = ($dateTimeFactory->createDateTime())->setISODate($year, $week, 1)->setTime(0, 0, 0);
|
||||
}
|
||||
|
||||
@@ -111,7 +130,7 @@ final class PaginatedWorkingTimeChart extends AbstractWidget
|
||||
|
||||
$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->getStatistic(TimesheetRepository::STATS_QUERY_DURATION, $yearBegin, $yearEnd, $user);
|
||||
$yearData = $this->repository->getDurationForTimeRange($yearBegin, $yearEnd, $user);
|
||||
|
||||
$financialYearData = null;
|
||||
$financialYearBegin = null;
|
||||
@@ -119,7 +138,7 @@ final class PaginatedWorkingTimeChart extends AbstractWidget
|
||||
if (null !== ($financialYear = $this->systemConfiguration->getFinancialYearStart())) {
|
||||
$financialYearBegin = $dateTimeFactory->createStartOfFinancialYear($financialYear);
|
||||
$financialYearEnd = $dateTimeFactory->createEndOfFinancialYear($financialYearBegin);
|
||||
$financialYearData = $this->repository->getStatistic(TimesheetRepository::STATS_QUERY_DURATION, $financialYearBegin, $financialYearEnd, $user);
|
||||
$financialYearData = $this->repository->getDurationForTimeRange($financialYearBegin, $financialYearEnd, $user);
|
||||
}
|
||||
|
||||
return [
|
||||
@@ -128,9 +147,9 @@ final class PaginatedWorkingTimeChart extends AbstractWidget
|
||||
'thisMonth' => $thisMonth,
|
||||
'lastWeekInYear' => $lastWeekInYear,
|
||||
'lastWeekInLastYear' => $lastWeekInLastYear,
|
||||
'day' => $this->repository->getStatistic(TimesheetRepository::STATS_QUERY_DURATION, $dayBegin, $dayEnd, $user),
|
||||
'week' => $this->repository->getStatistic(TimesheetRepository::STATS_QUERY_DURATION, $weekBegin, $weekEnd, $user),
|
||||
'month' => $this->repository->getStatistic(TimesheetRepository::STATS_QUERY_DURATION, $monthBegin, $monthEnd, $user),
|
||||
'day' => $this->repository->getDurationForTimeRange($dayBegin, $dayEnd, $user),
|
||||
'week' => $this->repository->getDurationForTimeRange($weekBegin, $weekEnd, $user),
|
||||
'month' => $this->repository->getDurationForTimeRange($monthBegin, $monthEnd, $user),
|
||||
'year' => $yearData,
|
||||
'financial' => $financialYearData,
|
||||
'financialBegin' => $financialYearBegin,
|
||||
|
||||
@@ -24,6 +24,10 @@ final class TotalsActivity extends AbstractWidget
|
||||
return 'stats.activityTotal';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string|bool|int|null> $options
|
||||
* @return array<string, string|bool|int|null>
|
||||
*/
|
||||
public function getOptions(array $options = []): array
|
||||
{
|
||||
return array_merge([
|
||||
@@ -33,6 +37,9 @@ final class TotalsActivity extends AbstractWidget
|
||||
], parent::getOptions($options));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string|bool|int|null> $options
|
||||
*/
|
||||
public function getData(array $options = []): mixed
|
||||
{
|
||||
$user = $this->getUser();
|
||||
|
||||
@@ -24,6 +24,10 @@ final class TotalsCustomer extends AbstractWidget
|
||||
return 'stats.customerTotal';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string|bool|int|null> $options
|
||||
* @return array<string, string|bool|int|null>
|
||||
*/
|
||||
public function getOptions(array $options = []): array
|
||||
{
|
||||
return array_merge([
|
||||
@@ -33,6 +37,9 @@ final class TotalsCustomer extends AbstractWidget
|
||||
], parent::getOptions($options));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string|bool|int|null> $options
|
||||
*/
|
||||
public function getData(array $options = []): mixed
|
||||
{
|
||||
$user = $this->getUser();
|
||||
|
||||
@@ -24,6 +24,10 @@ final class TotalsProject extends AbstractWidget
|
||||
return 'stats.projectTotal';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string|bool|int|null> $options
|
||||
* @return array<string, string|bool|int|null>
|
||||
*/
|
||||
public function getOptions(array $options = []): array
|
||||
{
|
||||
return array_merge([
|
||||
@@ -33,6 +37,9 @@ final class TotalsProject extends AbstractWidget
|
||||
], parent::getOptions($options));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string|bool|int|null> $options
|
||||
*/
|
||||
public function getData(array $options = []): mixed
|
||||
{
|
||||
$user = $this->getUser();
|
||||
|
||||
@@ -19,6 +19,10 @@ final class TotalsUser extends AbstractWidget
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string|bool|int|null> $options
|
||||
* @return array<string, string|bool|int|null>
|
||||
*/
|
||||
public function getOptions(array $options = []): array
|
||||
{
|
||||
return array_merge([
|
||||
@@ -28,6 +32,9 @@ final class TotalsUser extends AbstractWidget
|
||||
], parent::getOptions($options));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string|bool|int|null> $options
|
||||
*/
|
||||
public function getData(array $options = []): mixed
|
||||
{
|
||||
$user = $this->getUser();
|
||||
|
||||
@@ -13,6 +13,10 @@ use App\Widget\WidgetInterface;
|
||||
|
||||
final class UserAmountMonth extends AbstractUserRevenuePeriod
|
||||
{
|
||||
/**
|
||||
* @param array<string, string|bool|int|null> $options
|
||||
* @return array<string, string|bool|int|null>
|
||||
*/
|
||||
public function getOptions(array $options = []): array
|
||||
{
|
||||
return array_merge(['color' => WidgetInterface::COLOR_MONTH], parent::getOptions($options));
|
||||
@@ -23,8 +27,11 @@ final class UserAmountMonth extends AbstractUserRevenuePeriod
|
||||
return 'UserAmountMonth';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string|bool|int|null> $options
|
||||
*/
|
||||
public function getData(array $options = []): mixed
|
||||
{
|
||||
return $this->getRevenue('first day of this month 00:00:00', 'last day of this month 23:59:59', $options);
|
||||
return $this->getRevenue($this->createMonthStartDate(), $this->createMonthEndDate(), $options);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,10 @@ use App\Widget\WidgetInterface;
|
||||
|
||||
final class UserAmountToday extends AbstractUserRevenuePeriod
|
||||
{
|
||||
/**
|
||||
* @param array<string, string|bool|int|null> $options
|
||||
* @return array<string, string|bool|int|null>
|
||||
*/
|
||||
public function getOptions(array $options = []): array
|
||||
{
|
||||
return array_merge(['color' => WidgetInterface::COLOR_TODAY], parent::getOptions($options));
|
||||
@@ -23,8 +27,11 @@ final class UserAmountToday extends AbstractUserRevenuePeriod
|
||||
return 'UserAmountToday';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string|bool|int|null> $options
|
||||
*/
|
||||
public function getData(array $options = []): mixed
|
||||
{
|
||||
return $this->getRevenue('00:00:00', '23:59:59', $options);
|
||||
return $this->getRevenue($this->createTodayStartDate(), $this->createTodayEndDate(), $options);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,10 @@ use App\Widget\WidgetInterface;
|
||||
|
||||
final class UserAmountTotal extends AbstractUserRevenuePeriod
|
||||
{
|
||||
/**
|
||||
* @param array<string, string|bool|int|null> $options
|
||||
* @return array<string, string|bool|int|null>
|
||||
*/
|
||||
public function getOptions(array $options = []): array
|
||||
{
|
||||
return array_merge(['color' => WidgetInterface::COLOR_TOTAL], parent::getOptions($options));
|
||||
@@ -23,6 +27,9 @@ final class UserAmountTotal extends AbstractUserRevenuePeriod
|
||||
return 'UserAmountTotal';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string|bool|int|null> $options
|
||||
*/
|
||||
public function getData(array $options = []): mixed
|
||||
{
|
||||
return $this->getRevenue(null, null, $options);
|
||||
|
||||
@@ -13,6 +13,10 @@ use App\Widget\WidgetInterface;
|
||||
|
||||
final class UserAmountWeek extends AbstractUserRevenuePeriod
|
||||
{
|
||||
/**
|
||||
* @param array<string, string|bool|int|null> $options
|
||||
* @return array<string, string|bool|int|null>
|
||||
*/
|
||||
public function getOptions(array $options = []): array
|
||||
{
|
||||
return array_merge(['color' => WidgetInterface::COLOR_WEEK], parent::getOptions($options));
|
||||
@@ -23,8 +27,11 @@ final class UserAmountWeek extends AbstractUserRevenuePeriod
|
||||
return 'UserAmountWeek';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string|bool|int|null> $options
|
||||
*/
|
||||
public function getData(array $options = []): mixed
|
||||
{
|
||||
return $this->getRevenue('monday this week 00:00:00', 'sunday this week 23:59:59', $options);
|
||||
return $this->getRevenue($this->createWeekStartDate(), $this->createWeekEndDate(), $options);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,14 +13,15 @@ use App\Configuration\SystemConfiguration;
|
||||
use App\Event\UserRevenueStatisticEvent;
|
||||
use App\Model\Revenue;
|
||||
use App\Repository\TimesheetRepository;
|
||||
use App\Widget\WidgetException;
|
||||
use App\Widget\WidgetInterface;
|
||||
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
|
||||
|
||||
final class UserAmountYear extends AbstractCounterYear
|
||||
{
|
||||
public function __construct(TimesheetRepository $repository, SystemConfiguration $systemConfiguration, private EventDispatcherInterface $dispatcher)
|
||||
public function __construct(private TimesheetRepository $repository, SystemConfiguration $systemConfiguration, private EventDispatcherInterface $dispatcher)
|
||||
{
|
||||
parent::__construct($repository, $systemConfiguration);
|
||||
parent::__construct($systemConfiguration);
|
||||
}
|
||||
|
||||
public function getTemplateName(): string
|
||||
@@ -43,6 +44,10 @@ final class UserAmountYear extends AbstractCounterYear
|
||||
return 'UserAmountYear';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string|bool|int|null> $options
|
||||
* @return array<string, string|bool|int|null>
|
||||
*/
|
||||
public function getOptions(array $options = []): array
|
||||
{
|
||||
return array_merge([
|
||||
@@ -51,20 +56,26 @@ final class UserAmountYear extends AbstractCounterYear
|
||||
], parent::getOptions($options));
|
||||
}
|
||||
|
||||
public function getData(array $options = []): mixed
|
||||
/**
|
||||
* @param array<string, string|bool|int|null> $options
|
||||
*/
|
||||
protected function getYearData(\DateTimeInterface $begin, \DateTimeInterface $end, array $options = []): mixed
|
||||
{
|
||||
$this->setQuery(TimesheetRepository::STATS_QUERY_RATE);
|
||||
$this->setQueryWithUser(true);
|
||||
try {
|
||||
/** @var array<Revenue> $data */
|
||||
$data = $this->repository->getRevenue($begin, $end, $this->getUser());
|
||||
|
||||
/** @var array<Revenue> $data */
|
||||
$data = parent::getData($options);
|
||||
$event = new UserRevenueStatisticEvent($this->getUser(), $begin, $end);
|
||||
foreach ($data as $row) {
|
||||
$event->addRevenue($row->getCurrency(), $row->getAmount());
|
||||
}
|
||||
$this->dispatcher->dispatch($event);
|
||||
|
||||
$event = new UserRevenueStatisticEvent($this->getUser(), $this->getBegin(), $this->getEnd());
|
||||
foreach ($data as $row) {
|
||||
$event->addRevenue($row->getCurrency(), $row->getAmount());
|
||||
return $event->getRevenue();
|
||||
} catch (\Exception $ex) {
|
||||
throw new WidgetException(
|
||||
'Failed loading widget data: ' . $ex->getMessage()
|
||||
);
|
||||
}
|
||||
$this->dispatcher->dispatch($event);
|
||||
|
||||
return $event->getRevenue();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,10 +9,20 @@
|
||||
|
||||
namespace App\Widget\Type;
|
||||
|
||||
use App\Repository\TimesheetRepository;
|
||||
use App\Widget\WidgetException;
|
||||
use App\Widget\WidgetInterface;
|
||||
|
||||
final class UserDurationMonth extends AbstractCounterDuration
|
||||
{
|
||||
public function __construct(private TimesheetRepository $repository)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string|bool|int|null> $options
|
||||
* @return array<string, string|bool|int|null>
|
||||
*/
|
||||
public function getOptions(array $options = []): array
|
||||
{
|
||||
return array_merge(['color' => WidgetInterface::COLOR_MONTH], parent::getOptions($options));
|
||||
@@ -28,12 +38,17 @@ final class UserDurationMonth extends AbstractCounterDuration
|
||||
return 'userDurationMonth';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string|bool|int|null> $options
|
||||
*/
|
||||
public function getData(array $options = []): mixed
|
||||
{
|
||||
$this->setQueryWithUser(true);
|
||||
$this->setBegin('first day of this month 00:00:00');
|
||||
$this->setEnd('last day of this month 23:59:59');
|
||||
|
||||
return parent::getData($options);
|
||||
try {
|
||||
return $this->repository->getDurationForTimeRange($this->createMonthStartDate(), $this->createMonthEndDate(), $this->getUser());
|
||||
} catch (\Exception $ex) {
|
||||
throw new WidgetException(
|
||||
'Failed loading widget data: ' . $ex->getMessage()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,10 +9,20 @@
|
||||
|
||||
namespace App\Widget\Type;
|
||||
|
||||
use App\Repository\TimesheetRepository;
|
||||
use App\Widget\WidgetException;
|
||||
use App\Widget\WidgetInterface;
|
||||
|
||||
final class UserDurationToday extends AbstractCounterDuration
|
||||
{
|
||||
public function __construct(private TimesheetRepository $repository)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string|bool|int|null> $options
|
||||
* @return array<string, string|bool|int|null>
|
||||
*/
|
||||
public function getOptions(array $options = []): array
|
||||
{
|
||||
return array_merge(['color' => WidgetInterface::COLOR_TODAY], parent::getOptions($options));
|
||||
@@ -28,12 +38,17 @@ final class UserDurationToday extends AbstractCounterDuration
|
||||
return 'userDurationToday';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string|bool|int|null> $options
|
||||
*/
|
||||
public function getData(array $options = []): mixed
|
||||
{
|
||||
$this->setQueryWithUser(true);
|
||||
$this->setBegin('00:00:00');
|
||||
$this->setEnd('23:59:59');
|
||||
|
||||
return parent::getData($options);
|
||||
try {
|
||||
return $this->repository->getDurationForTimeRange($this->createTodayStartDate(), $this->createTodayEndDate(), $this->getUser());
|
||||
} catch (\Exception $ex) {
|
||||
throw new WidgetException(
|
||||
'Failed loading widget data: ' . $ex->getMessage()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,10 +9,20 @@
|
||||
|
||||
namespace App\Widget\Type;
|
||||
|
||||
use App\Repository\TimesheetRepository;
|
||||
use App\Widget\WidgetException;
|
||||
use App\Widget\WidgetInterface;
|
||||
|
||||
final class UserDurationTotal extends AbstractCounterDuration
|
||||
{
|
||||
public function __construct(private TimesheetRepository $repository)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string|bool|int|null> $options
|
||||
* @return array<string, string|bool|int|null>
|
||||
*/
|
||||
public function getOptions(array $options = []): array
|
||||
{
|
||||
return array_merge(['color' => WidgetInterface::COLOR_TOTAL], parent::getOptions($options));
|
||||
@@ -28,10 +38,17 @@ final class UserDurationTotal extends AbstractCounterDuration
|
||||
return 'userDurationTotal';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string|bool|int|null> $options
|
||||
*/
|
||||
public function getData(array $options = []): mixed
|
||||
{
|
||||
$this->setQueryWithUser(true);
|
||||
|
||||
return parent::getData($options);
|
||||
try {
|
||||
return $this->repository->getDurationForTimeRange(null, null, $this->getUser());
|
||||
} catch (\Exception $ex) {
|
||||
throw new WidgetException(
|
||||
'Failed loading widget data: ' . $ex->getMessage()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,10 +9,20 @@
|
||||
|
||||
namespace App\Widget\Type;
|
||||
|
||||
use App\Repository\TimesheetRepository;
|
||||
use App\Widget\WidgetException;
|
||||
use App\Widget\WidgetInterface;
|
||||
|
||||
final class UserDurationWeek extends AbstractCounterDuration
|
||||
{
|
||||
public function __construct(private TimesheetRepository $repository)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string|bool|int|null> $options
|
||||
* @return array<string, string|bool|int|null>
|
||||
*/
|
||||
public function getOptions(array $options = []): array
|
||||
{
|
||||
return array_merge(['color' => WidgetInterface::COLOR_WEEK], parent::getOptions($options));
|
||||
@@ -28,12 +38,17 @@ final class UserDurationWeek extends AbstractCounterDuration
|
||||
return 'userDurationWeek';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string|bool|int|null> $options
|
||||
*/
|
||||
public function getData(array $options = []): mixed
|
||||
{
|
||||
$this->setQueryWithUser(true);
|
||||
$this->setBegin('monday this week 00:00:00');
|
||||
$this->setEnd('sunday this week 23:59:59');
|
||||
|
||||
return parent::getData($options);
|
||||
try {
|
||||
return $this->repository->getDurationForTimeRange($this->createWeekStartDate(), $this->createWeekEndDate(), $this->getUser());
|
||||
} catch (\Exception $ex) {
|
||||
throw new WidgetException(
|
||||
'Failed loading widget data: ' . $ex->getMessage()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,11 +9,18 @@
|
||||
|
||||
namespace App\Widget\Type;
|
||||
|
||||
use App\Configuration\SystemConfiguration;
|
||||
use App\Repository\TimesheetRepository;
|
||||
use App\Widget\WidgetException;
|
||||
use App\Widget\WidgetInterface;
|
||||
|
||||
final class UserDurationYear extends AbstractCounterYear
|
||||
{
|
||||
public function __construct(private TimesheetRepository $repository, SystemConfiguration $systemConfiguration)
|
||||
{
|
||||
parent::__construct($systemConfiguration);
|
||||
}
|
||||
|
||||
public function getId(): string
|
||||
{
|
||||
return 'userDurationYear';
|
||||
@@ -24,6 +31,10 @@ final class UserDurationYear extends AbstractCounterYear
|
||||
return 'widget/widget-counter-duration.html.twig';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string|bool|int|null> $options
|
||||
* @return array<string, string|bool|int|null>
|
||||
*/
|
||||
public function getOptions(array $options = []): array
|
||||
{
|
||||
return array_merge([
|
||||
@@ -32,12 +43,18 @@ final class UserDurationYear extends AbstractCounterYear
|
||||
], parent::getOptions($options));
|
||||
}
|
||||
|
||||
public function getData(array $options = []): mixed
|
||||
/**
|
||||
* @param array<string, string|bool|int|null> $options
|
||||
*/
|
||||
protected function getYearData(\DateTimeInterface $begin, \DateTimeInterface $end, array $options = []): mixed
|
||||
{
|
||||
$this->setQuery(TimesheetRepository::STATS_QUERY_DURATION);
|
||||
$this->setQueryWithUser(true);
|
||||
|
||||
return parent::getData($options);
|
||||
try {
|
||||
return $this->repository->getDurationForTimeRange($begin, $end, $this->getUser());
|
||||
} catch (\Exception $ex) {
|
||||
throw new WidgetException(
|
||||
'Failed loading widget data: ' . $ex->getMessage()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
protected function getFinancialYearTitle(): string
|
||||
|
||||
@@ -59,6 +59,9 @@ final class UserTeamProjects extends AbstractWidget
|
||||
return 'UserTeamProjects';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string|bool|int|null> $options
|
||||
*/
|
||||
public function getData(array $options = []): mixed
|
||||
{
|
||||
$user = $this->getUser();
|
||||
|
||||
@@ -52,6 +52,9 @@ final class UserTeams extends AbstractWidget
|
||||
return 'UserTeams';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string|bool|int|null> $options
|
||||
*/
|
||||
public function getData(array $options = []): mixed
|
||||
{
|
||||
$user = $this->getUser();
|
||||
|
||||
@@ -71,10 +71,10 @@ interface WidgetInterface
|
||||
* make sure that the given $options will overwrite the internal option for
|
||||
* this one call.
|
||||
*
|
||||
* @param array $options
|
||||
* @param array<string, string|bool|int|null> $options
|
||||
* @return mixed|null
|
||||
*/
|
||||
public function getData(array $options = []);
|
||||
public function getData(array $options = []): mixed;
|
||||
|
||||
/**
|
||||
* Returns all widget options to be used in the frontend.
|
||||
@@ -86,7 +86,7 @@ interface WidgetInterface
|
||||
* return array_merge($this->options, $options);
|
||||
*
|
||||
* @param array<string, string|bool|int|null> $options
|
||||
* @return array<string, string|bool|int|null|null>
|
||||
* @return array<string, string|bool|int|null>
|
||||
*/
|
||||
public function getOptions(array $options = []): array;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user