vendor/easycorp/easyadmin-bundle/src/Config/Crud.php line 317

Open in your IDE?
  1. <?php
  2. namespace EasyCorp\Bundle\EasyAdminBundle\Config;
  3. use EasyCorp\Bundle\EasyAdminBundle\Config\Option\SortOrder;
  4. use EasyCorp\Bundle\EasyAdminBundle\Dto\CrudDto;
  5. use EasyCorp\Bundle\EasyAdminBundle\Dto\PaginatorDto;
  6. use EasyCorp\Bundle\EasyAdminBundle\Field\DateTimeField;
  7. /**
  8. * @author Javier Eguiluz <javier.eguiluz@gmail.com>
  9. */
  10. class Crud
  11. {
  12. public const PAGE_DETAIL = 'detail';
  13. public const PAGE_EDIT = 'edit';
  14. public const PAGE_INDEX = 'index';
  15. public const PAGE_NEW = 'new';
  16. public const LAYOUT_CONTENT_DEFAULT = 'normal';
  17. public const LAYOUT_CONTENT_FULL = 'full';
  18. public const LAYOUT_SIDEBAR_DEFAULT = 'normal';
  19. public const LAYOUT_SIDEBAR_COMPACT = 'compact';
  20. /** @var CrudDto */
  21. private $dto;
  22. private $paginatorPageSize = 20;
  23. private $paginatorRangeSize = 3;
  24. private $paginatorFetchJoinCollection = true;
  25. private $paginatorUseOutputWalkers;
  26. private function __construct(CrudDto $crudDto)
  27. {
  28. $this->dto = $crudDto;
  29. }
  30. public static function new(): self
  31. {
  32. $dto = new CrudDto();
  33. return new self($dto);
  34. }
  35. /**
  36. * @param string|callable $label The callable signature is: fn ($entityInstance, $pageName): string
  37. */
  38. public function setEntityLabelInSingular($label): self
  39. {
  40. $this->dto->setEntityLabelInSingular($label);
  41. return $this;
  42. }
  43. /**
  44. * @param string|callable $label The callable signature is: fn ($entityInstance, $pageName): string
  45. */
  46. public function setEntityLabelInPlural($label): self
  47. {
  48. $this->dto->setEntityLabelInPlural($label);
  49. return $this;
  50. }
  51. /**
  52. * @param string|callable $title The callable signature is: fn ($entityInstance): string
  53. */
  54. public function setPageTitle(string $pageName, $title): self
  55. {
  56. if (!\in_array($pageName, $this->getValidPageNames(), true)) {
  57. throw new \InvalidArgumentException(sprintf('The first argument of the "%s()" method must be one of these valid page names: %s ("%s" given).', __METHOD__, implode(', ', $this->getValidPageNames()), $pageName));
  58. }
  59. $this->dto->setCustomPageTitle($pageName, $title);
  60. return $this;
  61. }
  62. public function setHelp(string $pageName, string $helpMessage): self
  63. {
  64. if (!\in_array($pageName, $this->getValidPageNames(), true)) {
  65. throw new \InvalidArgumentException(sprintf('The first argument of the "%s()" method must be one of these valid page names: %s ("%s" given).', __METHOD__, implode(', ', $this->getValidPageNames()), $pageName));
  66. }
  67. $this->dto->setHelpMessage($pageName, $helpMessage);
  68. return $this;
  69. }
  70. /**
  71. * @param string $formatOrPattern A format name ('short', 'medium', 'long', 'full') or a valid ICU Datetime Pattern (see https://unicode-org.github.io/icu/userguide/format_parse/datetime/)
  72. */
  73. public function setDateFormat(string $formatOrPattern): self
  74. {
  75. if (DateTimeField::FORMAT_NONE === $formatOrPattern || '' === trim($formatOrPattern)) {
  76. $validDateFormatsWithoutNone = array_filter(DateTimeField::VALID_DATE_FORMATS, static function ($format) {
  77. return DateTimeField::FORMAT_NONE !== $format;
  78. });
  79. throw new \InvalidArgumentException(sprintf('The first argument of the "%s()" method cannot be "%s" or an empty string. Use either the special date formats (%s) or a datetime Intl pattern.', __METHOD__, DateTimeField::FORMAT_NONE, implode(', ', $validDateFormatsWithoutNone)));
  80. }
  81. $datePattern = DateTimeField::INTL_DATE_PATTERNS[$formatOrPattern] ?? $formatOrPattern;
  82. $this->dto->setDatePattern($datePattern);
  83. return $this;
  84. }
  85. /**
  86. * @param string $formatOrPattern A format name ('short', 'medium', 'long', 'full') or a valid ICU Datetime Pattern (see https://unicode-org.github.io/icu/userguide/format_parse/datetime/)
  87. */
  88. public function setTimeFormat(string $formatOrPattern): self
  89. {
  90. if (DateTimeField::FORMAT_NONE === $formatOrPattern || '' === trim($formatOrPattern)) {
  91. $validTimeFormatsWithoutNone = array_filter(DateTimeField::VALID_DATE_FORMATS, static function ($format) {
  92. return DateTimeField::FORMAT_NONE !== $format;
  93. });
  94. throw new \InvalidArgumentException(sprintf('The first argument of the "%s()" method cannot be "%s" or an empty string. Use either the special time formats (%s) or a datetime Intl pattern.', __METHOD__, DateTimeField::FORMAT_NONE, implode(', ', $validTimeFormatsWithoutNone)));
  95. }
  96. $timePattern = DateTimeField::INTL_TIME_PATTERNS[$formatOrPattern] ?? $formatOrPattern;
  97. $this->dto->setTimePattern($timePattern);
  98. return $this;
  99. }
  100. /**
  101. * @param string $dateFormatOrPattern A format name ('none', 'short', 'medium', 'long', 'full') or a valid ICU Datetime Pattern (see https://unicode-org.github.io/icu/userguide/format_parse/datetime/)
  102. * @param string $timeFormat A format name ('none', 'short', 'medium', 'long', 'full')
  103. */
  104. public function setDateTimeFormat(string $dateFormatOrPattern, string $timeFormat = DateTimeField::FORMAT_NONE): self
  105. {
  106. if ('' === trim($dateFormatOrPattern)) {
  107. throw new \InvalidArgumentException(sprintf('The first argument of the "%s()" method cannot be an empty string. Use either a date format (%s) or a datetime Intl pattern.', __METHOD__, implode(', ', DateTimeField::VALID_DATE_FORMATS)));
  108. }
  109. $datePatternIsEmpty = DateTimeField::FORMAT_NONE === $dateFormatOrPattern || '' === trim($dateFormatOrPattern);
  110. $timePatternIsEmpty = DateTimeField::FORMAT_NONE === $timeFormat || '' === trim($timeFormat);
  111. if ($datePatternIsEmpty && $timePatternIsEmpty) {
  112. throw new \InvalidArgumentException(sprintf('The values of the arguments of "%s()" cannot be "%s" or an empty string at the same time. Change any of them (or both).', __METHOD__, DateTimeField::FORMAT_NONE));
  113. }
  114. // when date format/pattern is none and time format is a pattern,
  115. // silently turn them into a datetime pattern
  116. if (DateTimeField::FORMAT_NONE === $dateFormatOrPattern && !\in_array($timeFormat, DateTimeField::VALID_DATE_FORMATS, true)) {
  117. $dateFormatOrPattern = $timeFormat;
  118. $timeFormat = DateTimeField::FORMAT_NONE;
  119. }
  120. $isDatePattern = !\in_array($dateFormatOrPattern, DateTimeField::VALID_DATE_FORMATS, true);
  121. if ($isDatePattern && DateTimeField::FORMAT_NONE !== $timeFormat) {
  122. throw new \InvalidArgumentException(sprintf('When the first argument of "%s()" is a datetime pattern, you cannot set the time format in the second argument (define the time format inside the datetime pattern).', __METHOD__));
  123. }
  124. if (!$isDatePattern && !\in_array($timeFormat, DateTimeField::VALID_DATE_FORMATS, true)) {
  125. throw new \InvalidArgumentException(sprintf('The value of the time format can only be one of the following: %s (but "%s" was given).', implode(', ', DateTimeField::VALID_DATE_FORMATS), $timeFormat));
  126. }
  127. $this->dto->setDateTimePattern($dateFormatOrPattern, $timeFormat);
  128. return $this;
  129. }
  130. public function setDateIntervalFormat(string $format): self
  131. {
  132. $this->dto->setDateIntervalFormat($format);
  133. return $this;
  134. }
  135. public function setTimezone(string $timezoneId): self
  136. {
  137. if (!\in_array($timezoneId, timezone_identifiers_list(), true)) {
  138. throw new \InvalidArgumentException(sprintf('The "%s" timezone is not a valid PHP timezone ID. Use any of the values listed at https://www.php.net/manual/en/timezones.php', $timezoneId));
  139. }
  140. $this->dto->setTimezone($timezoneId);
  141. return $this;
  142. }
  143. public function setNumberFormat(string $format): self
  144. {
  145. $this->dto->setNumberFormat($format);
  146. return $this;
  147. }
  148. /**
  149. * @param array $sortFieldsAndOrder ['fieldName' => 'ASC|DESC', ...]
  150. */
  151. public function setDefaultSort(array $sortFieldsAndOrder): self
  152. {
  153. $sortFieldsAndOrder = array_map('strtoupper', $sortFieldsAndOrder);
  154. foreach ($sortFieldsAndOrder as $sortField => $sortOrder) {
  155. if (!\in_array($sortOrder, [SortOrder::ASC, SortOrder::DESC], true)) {
  156. throw new \InvalidArgumentException(sprintf('The sort order can be only "%s" or "%s", "%s" given.', SortOrder::ASC, SortOrder::DESC, $sortOrder));
  157. }
  158. if (!\is_string($sortField)) {
  159. throw new \InvalidArgumentException(sprintf('The keys of the array that defines the default sort must be strings with the field names, but the given "%s" value is a "%s".', $sortField, \gettype($sortField)));
  160. }
  161. }
  162. $this->dto->setDefaultSort($sortFieldsAndOrder);
  163. return $this;
  164. }
  165. public function setSearchFields(?array $fieldNames): self
  166. {
  167. $this->dto->setSearchFields($fieldNames);
  168. return $this;
  169. }
  170. public function showEntityActionsAsDropdown(bool $showAsDropdown = true): self
  171. {
  172. trigger_deprecation('easycorp/easyadmin-bundle', '3.5.0', 'The "%s" method is deprecated because the default behavior changed to render entity actions as dropdown. Use "showEntityActionsInlined()" method if you want to revert this change.', __METHOD__);
  173. $this->dto->setShowEntityActionsAsDropdown($showAsDropdown);
  174. return $this;
  175. }
  176. public function showEntityActionsInlined(bool $showInlined = true): self
  177. {
  178. $this->dto->setShowEntityActionsAsDropdown(!$showInlined);
  179. return $this;
  180. }
  181. public function setFilters(?array $filters): self
  182. {
  183. $this->dto->setFiltersConfig($filters);
  184. return $this;
  185. }
  186. public function setPaginatorPageSize(int $maxResultsPerPage): self
  187. {
  188. if ($maxResultsPerPage < 1) {
  189. throw new \InvalidArgumentException('The minimum value of paginator page size is 1.');
  190. }
  191. $this->paginatorPageSize = $maxResultsPerPage;
  192. return $this;
  193. }
  194. public function setPaginatorRangeSize(int $maxPagesOnEachSide): self
  195. {
  196. if ($maxPagesOnEachSide < 0) {
  197. throw new \InvalidArgumentException('The minimum value of paginator range size is 0.');
  198. }
  199. $this->paginatorRangeSize = $maxPagesOnEachSide;
  200. return $this;
  201. }
  202. public function setPaginatorFetchJoinCollection(bool $fetchJoinCollection): self
  203. {
  204. $this->paginatorFetchJoinCollection = $fetchJoinCollection;
  205. return $this;
  206. }
  207. public function setPaginatorUseOutputWalkers(bool $useOutputWalkers): self
  208. {
  209. $this->paginatorUseOutputWalkers = $useOutputWalkers;
  210. return $this;
  211. }
  212. public function overrideTemplate(string $templateName, string $templatePath): self
  213. {
  214. $this->dto->overrideTemplate($templateName, $templatePath);
  215. return $this;
  216. }
  217. /**
  218. * Format: ['templateName' => 'templatePath', ...].
  219. */
  220. public function overrideTemplates(array $templateNamesAndPaths): self
  221. {
  222. foreach ($templateNamesAndPaths as $templateName => $templatePath) {
  223. $this->overrideTemplate($templateName, $templatePath);
  224. }
  225. return $this;
  226. }
  227. public function addFormTheme(string $themePath): self
  228. {
  229. // custom form themes are added last to give them more priority
  230. $this->dto->setFormThemes(array_merge($this->dto->getFormThemes(), [$themePath]));
  231. return $this;
  232. }
  233. public function setFormThemes(array $themePaths): self
  234. {
  235. foreach ($themePaths as $path) {
  236. if (!\is_string($path)) {
  237. throw new \InvalidArgumentException(sprintf('All form theme paths passed to the "%s" method must be strings, but at least one of those values is of type "%s".', __METHOD__, \gettype($path)));
  238. }
  239. }
  240. $this->dto->setFormThemes($themePaths);
  241. return $this;
  242. }
  243. public function setFormOptions(array $newFormOptions, array $editFormOptions = null): self
  244. {
  245. $this->dto->setNewFormOptions(KeyValueStore::new($newFormOptions));
  246. $this->dto->setEditFormOptions(KeyValueStore::new($editFormOptions ?? $newFormOptions));
  247. return $this;
  248. }
  249. public function setEntityPermission(string $permission): self
  250. {
  251. $this->dto->setEntityPermission($permission);
  252. return $this;
  253. }
  254. public function renderContentMaximized(bool $maximized = true): self
  255. {
  256. $this->dto->setContentWidth($maximized ? self::LAYOUT_CONTENT_FULL : self::LAYOUT_CONTENT_DEFAULT);
  257. return $this;
  258. }
  259. public function renderSidebarMinimized(bool $minimized = true): self
  260. {
  261. $this->dto->setSidebarWidth($minimized ? self::LAYOUT_SIDEBAR_COMPACT : self::LAYOUT_SIDEBAR_DEFAULT);
  262. return $this;
  263. }
  264. public function getAsDto(): CrudDto
  265. {
  266. $this->dto->setPaginator(new PaginatorDto($this->paginatorPageSize, $this->paginatorRangeSize, 1, $this->paginatorFetchJoinCollection, $this->paginatorUseOutputWalkers));
  267. return $this->dto;
  268. }
  269. private function getValidPageNames(): array
  270. {
  271. return [self::PAGE_DETAIL, self::PAGE_EDIT, self::PAGE_INDEX, self::PAGE_NEW];
  272. }
  273. }