[TASK] Allow generated BE user avatars to be cached
[Packages/TYPO3.CMS.git] / typo3 / sysext / backend / Classes / Backend / Avatar / Avatar.php
1 <?php
2 namespace TYPO3\CMS\Backend\Backend\Avatar;
3
4 /*
5 * This file is part of the TYPO3 CMS project.
6 *
7 * It is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License, either version 2
9 * of the License, or any later version.
10 *
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
13 *
14 * The TYPO3 project - inspiring people to share!
15 */
16
17 use TYPO3\CMS\Core\Cache\CacheManager;
18 use TYPO3\CMS\Core\Cache\Frontend\VariableFrontend;
19 use TYPO3\CMS\Core\Imaging\Icon;
20 use TYPO3\CMS\Core\Imaging\IconFactory;
21 use TYPO3\CMS\Core\Service\DependencyOrderingService;
22 use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
23 use TYPO3\CMS\Core\Utility\GeneralUtility;
24 use TYPO3\CMS\Fluid\View\StandaloneView;
25
26 /**
27 * Avatar renderer class
28 */
29 class Avatar
30 {
31 /**
32 * Array of sorted and initiated avatar providers
33 *
34 * @var AvatarProviderInterface[]
35 */
36 protected $avatarProviders = [];
37
38 /**
39 * Render avatar tag
40 *
41 * @param array $backendUser be_users record
42 * @param int $size width and height of the image
43 * @param bool $showIcon show the record icon
44 * @return string
45 */
46 public function render(array $backendUser = null, int $size = 32, bool $showIcon = false)
47 {
48
49 if (!is_array($backendUser)) {
50 $backendUser = $this->getBackendUser()->user;
51 }
52
53 $cacheId = 'avatar_' . md5(
54 $backendUser['uid'] . '/' .
55 (string)$size . '/' .
56 (string)$showIcon);
57
58 $avatar = static::getCache()->get($cacheId);
59
60 if (!$avatar) {
61
62 $this->validateSortAndInitiateAvatarProviders();
63 $view = $this->getFluidTemplateObject();
64
65 // Icon
66 $icon = '';
67 if ($showIcon) {
68 $iconFactory = GeneralUtility::makeInstance(IconFactory::class);
69 $icon = $iconFactory->getIconForRecord('be_users', $backendUser, Icon::SIZE_SMALL)->render();
70 }
71
72 $image = $this->getImgTag($backendUser, $size);
73
74 $view->assignMultiple(
75 [
76 'image' => $image,
77 'icon' => $icon
78 ]
79 );
80 $avatar = $view->render();
81 static::getCache()->set($cacheId, $avatar);
82 }
83
84 return $avatar;
85 }
86
87 /**
88 * Get avatar img tag
89 *
90 * @param array $backendUser be_users record
91 * @param int $size
92 * @return string
93 */
94 public function getImgTag(array $backendUser = null, $size = 32)
95 {
96 if (!is_array($backendUser)) {
97 $backendUser = $this->getBackendUser()->user;
98 }
99
100 $avatarImage = false;
101 if ($backendUser !== null) {
102 $avatarImage = $this->getImage($backendUser, $size);
103 }
104
105 if (!$avatarImage) {
106 $avatarImage = GeneralUtility::makeInstance(
107 Image::class,
108 ExtensionManagementUtility::siteRelPath('core') . 'Resources/Public/Icons/T3Icons/avatar/avatar-default.svg',
109 $size,
110 $size
111 );
112 }
113 $imageTag = '<img src="' . htmlspecialchars($avatarImage->getUrl(true)) . '" ' .
114 'width="' . (int)$avatarImage->getWidth() . '" ' .
115 'height="' . (int)$avatarImage->getHeight() . '" />';
116
117 return $imageTag;
118 }
119
120 /**
121 * Get Image from first provider that returns one
122 *
123 * @param array $backendUser be_users record
124 * @param int $size
125 * @return Image|NULL
126 */
127 public function getImage(array $backendUser, $size)
128 {
129 foreach ($this->avatarProviders as $provider) {
130 $avatarImage = $provider->getImage($backendUser, $size);
131 if (!empty($avatarImage)) {
132 return $avatarImage;
133 }
134 }
135 return null;
136 }
137
138 /**
139 * Validates the registered avatar providers
140 *
141 * @return void
142 * @throws \RuntimeException
143 */
144 protected function validateSortAndInitiateAvatarProviders()
145 {
146 if (
147 empty($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['backend']['avatarProviders'])
148 || !is_array($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['backend']['avatarProviders'])
149 ) {
150 return;
151 }
152 $providers = $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['backend']['avatarProviders'];
153 foreach ($providers as $identifier => $configuration) {
154 if (empty($configuration) || !is_array($configuration)) {
155 throw new \RuntimeException('Missing configuration for avatar provider "' . $identifier . '".', 1439317801);
156 }
157 if (!is_string($configuration['provider']) || empty($configuration['provider']) || !class_exists($configuration['provider']) || !is_subclass_of($configuration['provider'], AvatarProviderInterface::class)) {
158 throw new \RuntimeException('The avatar provider "' . $identifier . '" defines an invalid provider. Ensure the class exists and implements the "' . AvatarProviderInterface::class . '".', 1439317802);
159 }
160 }
161
162 $orderedProviders = GeneralUtility::makeInstance(DependencyOrderingService::class)->orderByDependencies($providers);
163
164 // Initiate providers
165 foreach ($orderedProviders as $configuration) {
166 $this->avatarProviders[] = GeneralUtility::makeInstance($configuration['provider']);
167 }
168 }
169
170 /**
171 * Returns the current BE user.
172 *
173 * @return \TYPO3\CMS\Core\Authentication\BackendUserAuthentication
174 */
175 protected function getBackendUser()
176 {
177 return $GLOBALS['BE_USER'];
178 }
179
180 /**
181 * Returns a new standalone view, shorthand function
182 *
183 * @param string $filename Which templateFile should be used.
184 *
185 * @return StandaloneView
186 */
187 protected function getFluidTemplateObject(string $filename = null):StandaloneView
188 {
189 /** @var StandaloneView $view */
190 $view = GeneralUtility::makeInstance(StandaloneView::class);
191 $view->setLayoutRootPaths([GeneralUtility::getFileAbsFileName('EXT:backend/Resources/Private/Layouts')]);
192 $view->setPartialRootPaths([GeneralUtility::getFileAbsFileName('EXT:backend/Resources/Private/Partials')]);
193 $view->setTemplateRootPaths([GeneralUtility::getFileAbsFileName('EXT:backend/Resources/Private/Templates')]);
194
195 if (is_null($filename)) {
196 $filename = 'Main.html';
197 }
198
199 $view->setTemplatePathAndFilename(GeneralUtility::getFileAbsFileName('EXT:backend/Resources/Private/Templates/Avatar/' . $filename));
200
201 $view->getRequest()->setControllerExtensionName('Backend');
202 return $view;
203 }
204
205 /**
206 * @return VariableFrontend
207 */
208 protected function getCache()
209 {
210 /** @var CacheManager $manager */
211 $manager = GeneralUtility::makeInstance(CacheManager::class);
212 return $manager->getCache('cache_runtime');
213 }
214 }