Manager.php 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. <?php
  2. declare(strict_types=1);
  3. /**
  4. * SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors
  5. * SPDX-License-Identifier: AGPL-3.0-or-later
  6. */
  7. namespace OC\Dashboard;
  8. use InvalidArgumentException;
  9. use OCP\App\IAppManager;
  10. use OCP\Dashboard\IConditionalWidget;
  11. use OCP\Dashboard\IManager;
  12. use OCP\Dashboard\IWidget;
  13. use Psr\Container\ContainerExceptionInterface;
  14. use Psr\Container\ContainerInterface;
  15. use Psr\Log\LoggerInterface;
  16. use Throwable;
  17. class Manager implements IManager {
  18. /** @var array */
  19. private $lazyWidgets = [];
  20. /** @var array<string, IWidget> */
  21. private array $widgets = [];
  22. private ContainerInterface $serverContainer;
  23. private ?IAppManager $appManager = null;
  24. public function __construct(ContainerInterface $serverContainer) {
  25. $this->serverContainer = $serverContainer;
  26. }
  27. private function registerWidget(IWidget $widget): void {
  28. if (array_key_exists($widget->getId(), $this->widgets)) {
  29. throw new InvalidArgumentException('Dashboard widget with this id has already been registered');
  30. }
  31. $this->widgets[$widget->getId()] = $widget;
  32. }
  33. public function lazyRegisterWidget(string $widgetClass, string $appId): void {
  34. $this->lazyWidgets[] = ['class' => $widgetClass, 'appId' => $appId];
  35. }
  36. public function loadLazyPanels(): void {
  37. if ($this->appManager === null) {
  38. $this->appManager = $this->serverContainer->get(IAppManager::class);
  39. }
  40. $services = $this->lazyWidgets;
  41. foreach ($services as $service) {
  42. /** @psalm-suppress InvalidCatch */
  43. try {
  44. if (!$this->appManager->isEnabledForUser($service['appId'])) {
  45. // all apps are registered, but some may not be enabled for the user
  46. continue;
  47. }
  48. /** @var IWidget $widget */
  49. $widget = $this->serverContainer->get($service['class']);
  50. } catch (ContainerExceptionInterface $e) {
  51. /*
  52. * There is a circular dependency between the logger and the registry, so
  53. * we can not inject it. Thus the static call.
  54. */
  55. \OC::$server->get(LoggerInterface::class)->critical(
  56. 'Could not load lazy dashboard widget: ' . $service['class'],
  57. ['exception' => $e]
  58. );
  59. continue;
  60. }
  61. /**
  62. * Try to register the loaded reporter. Theoretically it could be of a wrong
  63. * type, so we might get a TypeError here that we should catch.
  64. */
  65. try {
  66. if ($widget instanceof IConditionalWidget && !$widget->isEnabled()) {
  67. continue;
  68. }
  69. $this->registerWidget($widget);
  70. } catch (Throwable $e) {
  71. /*
  72. * There is a circular dependency between the logger and the registry, so
  73. * we can not inject it. Thus the static call.
  74. */
  75. \OC::$server->get(LoggerInterface::class)->critical(
  76. 'Could not register lazy dashboard widget: ' . $service['class'],
  77. ['exception' => $e]
  78. );
  79. continue;
  80. }
  81. try {
  82. $startTime = microtime(true);
  83. $widget->load();
  84. $endTime = microtime(true);
  85. $duration = $endTime - $startTime;
  86. if ($duration > 1) {
  87. \OC::$server->get(LoggerInterface::class)->info(
  88. 'Dashboard widget {widget} took {duration} seconds to load.',
  89. [
  90. 'widget' => $widget->getId(),
  91. 'duration' => round($duration, 2),
  92. ]
  93. );
  94. }
  95. } catch (Throwable $e) {
  96. \OC::$server->get(LoggerInterface::class)->critical(
  97. 'Error during dashboard widget loading: ' . $service['class'],
  98. ['exception' => $e]
  99. );
  100. continue;
  101. }
  102. }
  103. $this->lazyWidgets = [];
  104. }
  105. /**
  106. * @return array<string, IWidget>
  107. */
  108. public function getWidgets(): array {
  109. $this->loadLazyPanels();
  110. return $this->widgets;
  111. }
  112. }