mirror of
				https://gitlab.com/Chill-Projet/chill-bundles.git
				synced 2025-10-31 17:28:23 +00:00 
			
		
		
		
	Compare commits
	
		
			7 Commits
		
	
	
		
			451-activi
			...
			385-invita
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 74c9eb5585 | |||
| f93c7e014f | |||
| e6a799abc4 | |||
| 68a0ef7115 | |||
| 1675c56f3d | |||
| 675e8450fc | |||
| 4ffd7034d0 | 
							
								
								
									
										6
									
								
								.changes/unreleased/Feature-20250808-120802.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								.changes/unreleased/Feature-20250808-120802.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,6 @@ | ||||
| kind: Feature | ||||
| body: Create invitation list in user menu | ||||
| time: 2025-08-08T12:08:02.446361367+02:00 | ||||
| custom: | ||||
|     Issue: "385" | ||||
|     SchemaChange: No schema change | ||||
| @@ -266,7 +266,7 @@ class CalendarController extends AbstractController | ||||
|         } | ||||
|  | ||||
|         if (!$this->getUser() instanceof User) { | ||||
|             throw new UnauthorizedHttpException('you are not an user'); | ||||
|             throw new UnauthorizedHttpException('you are not a user'); | ||||
|         } | ||||
|  | ||||
|         $view = '@ChillCalendar/Calendar/listByUser.html.twig'; | ||||
|   | ||||
| @@ -0,0 +1,58 @@ | ||||
| <?php | ||||
|  | ||||
| declare(strict_types=1); | ||||
|  | ||||
| /* | ||||
|  * Chill is a software for social workers | ||||
|  * | ||||
|  * For the full copyright and license information, please view | ||||
|  * the LICENSE file that was distributed with this source code. | ||||
|  */ | ||||
|  | ||||
| namespace Chill\CalendarBundle\Controller; | ||||
|  | ||||
| use Chill\CalendarBundle\Entity\Calendar; | ||||
| use Chill\CalendarBundle\Repository\InviteRepository; | ||||
| use Chill\DocGeneratorBundle\Repository\DocGeneratorTemplateRepositoryInterface; | ||||
| use Chill\MainBundle\Entity\User; | ||||
| use Chill\MainBundle\Pagination\PaginatorFactory; | ||||
| use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; | ||||
| use Symfony\Component\HttpFoundation\Request; | ||||
| use Symfony\Component\HttpFoundation\Response; | ||||
| use Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException; | ||||
| use Symfony\Component\Routing\Annotation\Route; | ||||
|  | ||||
| class MyInvitationsController extends AbstractController | ||||
| { | ||||
|     public function __construct(private readonly InviteRepository $inviteRepository, private readonly PaginatorFactory $paginator, private readonly DocGeneratorTemplateRepositoryInterface $docGeneratorTemplateRepository) {} | ||||
|  | ||||
|     #[Route(path: '/{_locale}/calendar/invitations/my', name: 'chill_calendar_invitations_list_my')] | ||||
|     public function myInvitations(Request $request): Response | ||||
|     { | ||||
|         $this->denyAccessUnlessGranted('ROLE_USER'); | ||||
|  | ||||
|         $user = $this->getUser(); | ||||
|  | ||||
|         if (!$user instanceof User) { | ||||
|             throw new UnauthorizedHttpException('you are not a user'); | ||||
|         } | ||||
|  | ||||
|         $total = count($this->inviteRepository->findBy(['user' => $user])); | ||||
|         $paginator = $this->paginator->create($total); | ||||
|  | ||||
|         $invitations = $this->inviteRepository->findBy( | ||||
|             ['user' => $user], | ||||
|             ['createdAt' => 'DESC'], | ||||
|             $paginator->getItemsPerPage(), | ||||
|             $paginator->getCurrentPageFirstItemNumber() | ||||
|         ); | ||||
|  | ||||
|         $view = '@ChillCalendar/Invitations/listByUser.html.twig'; | ||||
|  | ||||
|         return $this->render($view, [ | ||||
|             'invitations' => $invitations, | ||||
|             'paginator' => $paginator, | ||||
|             'templates' => $this->docGeneratorTemplateRepository->findByEntity(Calendar::class), | ||||
|         ]); | ||||
|     } | ||||
| } | ||||
| @@ -30,6 +30,13 @@ class UserMenuBuilder implements LocalMenuBuilderInterface | ||||
|                     'order' => 9, | ||||
|                     'icon' => 'tasks', | ||||
|                 ]); | ||||
|             $menu->addChild('My invitations list', [ | ||||
|                 'route' => 'chill_calendar_invitations_list_my', | ||||
|             ]) | ||||
|                 ->setExtras([ | ||||
|                     'order' => 9, | ||||
|                     'icon' => 'tasks', | ||||
|                 ]); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -41,7 +41,7 @@ class InviteRepository implements ObjectRepository | ||||
|     /** | ||||
|      * @return array|Invite[] | ||||
|      */ | ||||
|     public function findBy(array $criteria, ?array $orderBy = null, ?int $limit = null, ?int $offset = null) | ||||
|     public function findBy(array $criteria, ?array $orderBy = null, ?int $limit = null, ?int $offset = null): array | ||||
|     { | ||||
|         return $this->entityRepository->findBy($criteria, $orderBy, $limit, $offset); | ||||
|     } | ||||
|   | ||||
| @@ -1,240 +1,229 @@ | ||||
| {# list used in context of person or accompanyingPeriod #} | ||||
| {# list used in context of person, accompanyingPeriod or user #} | ||||
|  | ||||
| {% if calendarItems|length > 0 %} | ||||
|     <div class="flex-table list-records context-accompanyingCourse"> | ||||
| <div class="item-bloc"> | ||||
|     <div class="item-row main"> | ||||
|         <div class="item-col"> | ||||
|             <div class="wrap-header"> | ||||
|                 <div class="wl-row"> | ||||
|                     <div class="wl-col title"> | ||||
|                         <p class="date-label"> | ||||
|                             {% if context == 'person' and calendar.context == 'accompanying_period' %} | ||||
|                                 <a href="{{ chill_path_add_return_path('chill_person_accompanying_course_index', {'accompanying_period_id': calendar.accompanyingPeriod.id}) }}" style="text-decoration: none;"> | ||||
|                                     <span class="badge bg-primary"> | ||||
|                                             <i class="fa fa-random"></i> {{ calendar.accompanyingPeriod.id }} | ||||
|                                     </span> | ||||
|                                 </a> | ||||
|                             {% endif %} | ||||
|                             {% if calendar.endDate.diff(calendar.startDate).days >= 1 %} | ||||
|                                     {{ calendar.startDate|format_datetime('short', 'short') }} | ||||
|                                     - {{ calendar.endDate|format_datetime('short', 'short') }} | ||||
|                             {% else %} | ||||
|                                 {{ calendar.startDate|format_datetime('short', 'short') }} | ||||
|                                     - {{ calendar.endDate|format_datetime('none', 'short') }} | ||||
|                             {% endif %} | ||||
|                         </p> | ||||
|  | ||||
|         {% for calendar in calendarItems %} | ||||
|  | ||||
|             <div class="item-bloc"> | ||||
|                 <div class="item-row main"> | ||||
|                     <div class="item-col"> | ||||
|                         <div class="wrap-header"> | ||||
|                             <div class="wl-row"> | ||||
|                                 <div class="wl-col title"> | ||||
|                                     <p class="date-label"> | ||||
|                                         {% if context == 'person' and calendar.context == 'accompanying_period' %} | ||||
|                                             <a href="{{ chill_path_add_return_path('chill_person_accompanying_course_index', {'accompanying_period_id': calendar.accompanyingPeriod.id}) }}" style="text-decoration: none;"> | ||||
|                                                 <span class="badge bg-primary"> | ||||
|                                                         <i class="fa fa-random"></i> {{ calendar.accompanyingPeriod.id }} | ||||
|                                                 </span> | ||||
|                                             </a> | ||||
|                                         {% endif %} | ||||
|                                         {% if calendar.endDate.diff(calendar.startDate).days >= 1 %} | ||||
|                                                 {{ calendar.startDate|format_datetime('short', 'short') }} | ||||
|                                                 - {{ calendar.endDate|format_datetime('short', 'short') }} | ||||
|                                         {% else %} | ||||
|                                             {{ calendar.startDate|format_datetime('short', 'short') }} | ||||
|                                                 - {{ calendar.endDate|format_datetime('none', 'short') }} | ||||
|                                         {% endif %} | ||||
|                                     </p> | ||||
|  | ||||
|                                     <div class="duration short-message"> | ||||
|                                         <i class="fa fa-fw fa-hourglass-end"></i> | ||||
|                                         {{ calendar.duration|date('%H:%I') }} | ||||
|                                         {% if false == calendar.sendSMS or null == calendar.sendSMS %} | ||||
|                                             <!-- no sms will be send --> | ||||
|                                         {% else %} | ||||
|                                             {% if calendar.smsStatus == 'sms_sent' %} | ||||
|                                                 <span title="{{ 'SMS already sent'|trans }}" class="badge bg-info"> | ||||
|                                                     <i class="fa fa-check "></i> | ||||
|                                                     <i class="fa fa-envelope "></i> | ||||
|                                                 </span> | ||||
|                                             {% else %} | ||||
|                                                 <span title="{{ 'Will send SMS'|trans }}" class="badge bg-info"> | ||||
|                                                     <i class="fa fa-envelope "></i> | ||||
|                                                     <i class="fa fa-hourglass-end "></i> | ||||
|                                                 </span> | ||||
|                                             {% endif %} | ||||
|                                         {% endif %} | ||||
|                                     </div> | ||||
|  | ||||
|                                 </div> | ||||
|                             </div> | ||||
|                         <div class="duration short-message"> | ||||
|                             <i class="fa fa-fw fa-hourglass-end"></i> | ||||
|                             {{ calendar.duration|date('%H:%I') }} | ||||
|                             {% if false == calendar.sendSMS or null == calendar.sendSMS %} | ||||
|                                 <!-- no sms will be send --> | ||||
|                             {% else %} | ||||
|                                 {% if calendar.smsStatus == 'sms_sent' %} | ||||
|                                     <span title="{{ 'SMS already sent'|trans }}" class="badge bg-info"> | ||||
|                                         <i class="fa fa-check "></i> | ||||
|                                         <i class="fa fa-envelope "></i> | ||||
|                                     </span> | ||||
|                                 {% else %} | ||||
|                                     <span title="{{ 'Will send SMS'|trans }}" class="badge bg-info"> | ||||
|                                         <i class="fa fa-envelope "></i> | ||||
|                                         <i class="fa fa-hourglass-end "></i> | ||||
|                                     </span> | ||||
|                                 {% endif %} | ||||
|                             {% endif %} | ||||
|                         </div> | ||||
|  | ||||
|                         <div class="item-col"> | ||||
|                             <ul class="list-content"> | ||||
|                                 {% if calendar.mainUser is not empty %} | ||||
|                                     <span class="badge-user">{{ calendar.mainUser|chill_entity_render_box({'at_date': calendar.startDate}) }}</span> | ||||
|                     </div> | ||||
|                 </div> | ||||
|             </div> | ||||
|  | ||||
|             <div class="item-col"> | ||||
|                 <ul class="list-content"> | ||||
|                     {% if calendar.mainUser is not empty %} | ||||
|                         <span class="badge-user">{{ calendar.mainUser|chill_entity_render_box({'at_date': calendar.startDate}) }}</span> | ||||
|                     {% endif %} | ||||
|                 </ul> | ||||
|             </div> | ||||
|  | ||||
|         </div> | ||||
|     </div> | ||||
|  | ||||
|     {% if calendar.comment.comment is not empty | ||||
|         or calendar.users|length > 0 | ||||
|         or calendar.thirdParties|length > 0 | ||||
|         or calendar.users|length > 0 %} | ||||
|         <div class="item-row details separator"> | ||||
|             <div class="item-col"> | ||||
|                 {% include '@ChillActivity/Activity/concernedGroups.html.twig' with { | ||||
|                     'context': calendar.context == 'person' ?  'calendar_person' : 'calendar_accompanyingCourse', | ||||
|                     'render': 'wrap-list', | ||||
|                     'entity': calendar | ||||
|                 } %} | ||||
|             </div> | ||||
|  | ||||
|         </div> | ||||
|     {% endif %} | ||||
|  | ||||
|     {% if calendar.comment.comment is not empty %} | ||||
|         <div class="item-row details separator"> | ||||
|             <div class="item-col comment"> | ||||
|                 {{ calendar.comment|chill_entity_render_box( { 'limit_lines': 3, 'metadata': false } ) }} | ||||
|             </div> | ||||
|         </div> | ||||
|     {% endif %} | ||||
|  | ||||
|     {% if calendar.location is not empty %} | ||||
|         <div class="item-row separator"> | ||||
|             <div> | ||||
|                 {% if calendar.location.address is not same as(null) and calendar.location.name is not empty %} | ||||
|                     <i class="fa fa-map-marker"></i>{% endif %} | ||||
|                 {% if calendar.location.name is not empty %}{{ calendar.location.name }}{% endif %} | ||||
|                 {% if calendar.location.address is not same as(null) %}{{ calendar.location.address|chill_entity_render_box({'multiline': false, 'with_picto': (calendar.location.name is empty)}) }}{% else %} | ||||
|                     <i class="fa fa-map-marker"></i>{% endif %} | ||||
|                 {% if calendar.location.phonenumber1 is not empty %}<i | ||||
|                     class="fa fa-phone"></i> {{ calendar.location.phonenumber1|chill_format_phonenumber }}{% endif %} | ||||
|                 {% if calendar.location.phonenumber2 is not empty %}<i | ||||
|                     class="fa fa-phone"></i> {{ calendar.location.phonenumber2|chill_format_phonenumber }}{% endif %} | ||||
|             </div> | ||||
|         </div> | ||||
|     {% endif %} | ||||
|  | ||||
|     <div class="item-row separator column"> | ||||
|         <div> | ||||
|  | ||||
|             {{ include('@ChillCalendar/Calendar/_documents.twig.html') }} | ||||
|         </div> | ||||
|     </div> | ||||
|  | ||||
|     {% if calendar.activity is not null %} | ||||
|         <div class="item-row separator"> | ||||
|             <div class="item-col"> | ||||
|                 <div class="wrap-list"> | ||||
|                     <div class="wl-row"> | ||||
|                         <div class="wl-col title"><h3>{{ 'Activity'|trans }}</h3></div> | ||||
|                         <div class="wl-col list activity-linked"> | ||||
|                             <h2 class="badge-title"> | ||||
|                                 <span class="title_label"></span> | ||||
|                                 <span class="title_action"> | ||||
|                                 {{ calendar.activity.type.name | localize_translatable_string }} | ||||
|  | ||||
|                                     {% if calendar.activity.emergency %} | ||||
|                                         <span class="badge bg-danger rounded-pill fs-6 float-end">{{ 'Emergency'|trans|upper }}</span> | ||||
|                                     {% endif %} | ||||
|                             </span> | ||||
|                             </h2> | ||||
|  | ||||
|                             <ul class="record_actions"> | ||||
|                                 <li class="cancel"> | ||||
|                                     <span class="createdBy"> | ||||
|                                          {{ 'Created by'|trans }} | ||||
|                                         <b>{{ calendar.activity.createdBy|chill_entity_render_string({'at_date': calendar.activity.createdAt}) }}</b>, {{ 'on'|trans }} {{ calendar.activity.createdAt|format_datetime('short', 'short') }} | ||||
|                                     </span> | ||||
|                                 </li> | ||||
|                                 {% if is_granted('CHILL_ACTIVITY_SEE', calendar.activity) %} | ||||
|                                     <li> | ||||
|                                         <a href="{{ chill_path_add_return_path('chill_activity_activity_show', {'id': calendar.activity.id}) }}" class="btn btn-sm btn-show" ></a> | ||||
|                                     </li> | ||||
|                                 {% endif %} | ||||
|                             </ul> | ||||
|                         </div> | ||||
|  | ||||
|                         </div> | ||||
|                     </div> | ||||
|                 </div> | ||||
|  | ||||
|                 {% if calendar.comment.comment is not empty | ||||
|                     or calendar.users|length > 0 | ||||
|                     or calendar.thirdParties|length > 0 | ||||
|                     or calendar.users|length > 0 %} | ||||
|                     <div class="item-row details separator"> | ||||
|                         <div class="item-col"> | ||||
|                             {% include '@ChillActivity/Activity/concernedGroups.html.twig' with { | ||||
|                                 'context': calendar.context == 'person' ?  'calendar_person' : 'calendar_accompanyingCourse', | ||||
|                                 'render': 'wrap-list', | ||||
|                                 'entity': calendar | ||||
|                             } %} | ||||
|                         </div> | ||||
|  | ||||
|                     </div> | ||||
|                 {% endif %} | ||||
|  | ||||
|                 {% if calendar.comment.comment is not empty %} | ||||
|                     <div class="item-row details separator"> | ||||
|                         <div class="item-col comment"> | ||||
|                             {{ calendar.comment|chill_entity_render_box( { 'limit_lines': 3, 'metadata': false } ) }} | ||||
|                         </div> | ||||
|                     </div> | ||||
|                 {% endif %} | ||||
|  | ||||
|                 {% if calendar.location is not empty %} | ||||
|                     <div class="item-row separator"> | ||||
|                         <div> | ||||
|                             {% if calendar.location.address is not same as(null) and calendar.location.name is not empty %} | ||||
|                                 <i class="fa fa-map-marker"></i>{% endif %} | ||||
|                             {% if calendar.location.name is not empty %}{{ calendar.location.name }}{% endif %} | ||||
|                             {% if calendar.location.address is not same as(null) %}{{ calendar.location.address|chill_entity_render_box({'multiline': false, 'with_picto': (calendar.location.name is empty)}) }}{% else %} | ||||
|                                 <i class="fa fa-map-marker"></i>{% endif %} | ||||
|                             {% if calendar.location.phonenumber1 is not empty %}<i | ||||
|                                 class="fa fa-phone"></i> {{ calendar.location.phonenumber1|chill_format_phonenumber }}{% endif %} | ||||
|                             {% if calendar.location.phonenumber2 is not empty %}<i | ||||
|                                 class="fa fa-phone"></i> {{ calendar.location.phonenumber2|chill_format_phonenumber }}{% endif %} | ||||
|                         </div> | ||||
|                     </div> | ||||
|                 {% endif %} | ||||
|  | ||||
|                 <div class="item-row separator column"> | ||||
|                     <div> | ||||
|  | ||||
|                         {{ include('@ChillCalendar/Calendar/_documents.twig.html') }} | ||||
|                     </div> | ||||
|                 </div> | ||||
|  | ||||
|                 {% if calendar.activity is not null %} | ||||
|                     <div class="item-row separator"> | ||||
|                         <div class="item-col"> | ||||
|                             <div class="wrap-list"> | ||||
|                                 <div class="wl-row"> | ||||
|                                     <div class="wl-col title"><h3>{{ 'Activity'|trans }}</h3></div> | ||||
|                                     <div class="wl-col list activity-linked"> | ||||
|                                         <h2 class="badge-title"> | ||||
|                                             <span class="title_label"></span> | ||||
|                                             <span class="title_action"> | ||||
|                                             {{ calendar.activity.type.name | localize_translatable_string }} | ||||
|  | ||||
|                                                 {% if calendar.activity.emergency %} | ||||
|                                                     <span class="badge bg-danger rounded-pill fs-6 float-end">{{ 'Emergency'|trans|upper }}</span> | ||||
|                                                 {% endif %} | ||||
|                                         </span> | ||||
|                                         </h2> | ||||
|  | ||||
|                                         <ul class="record_actions"> | ||||
|                                             <li class="cancel"> | ||||
|                                                 <span class="createdBy"> | ||||
|                                                      {{ 'Created by'|trans }} | ||||
|                                                     <b>{{ calendar.activity.createdBy|chill_entity_render_string({'at_date': calendar.activity.createdAt}) }}</b>, {{ 'on'|trans }} {{ calendar.activity.createdAt|format_datetime('short', 'short') }} | ||||
|                                                 </span> | ||||
|                                             </li> | ||||
|                                             {% if is_granted('CHILL_ACTIVITY_SEE', calendar.activity) %} | ||||
|                                                 <li> | ||||
|                                                     <a href="{{ chill_path_add_return_path('chill_activity_activity_show', {'id': calendar.activity.id}) }}" class="btn btn-sm btn-show" ></a> | ||||
|                                                 </li> | ||||
|                                             {% endif %} | ||||
|                                         </ul> | ||||
|  | ||||
|                                     </div> | ||||
|                                 </div> | ||||
|                             </div> | ||||
|                         </div> | ||||
|                     </div> | ||||
|                 {% endif %} | ||||
|  | ||||
|                 <div class="item-row separator"> | ||||
|                     <ul class="record_actions"> | ||||
|                         {% if is_granted('CHILL_CALENDAR_DOC_EDIT', calendar) %} | ||||
|                             {% if templates|length == 0 %} | ||||
|                                 <li> | ||||
|                                     <a class="btn btn-create" | ||||
|                                        href="{{ chill_path_add_return_path('chill_calendar_calendardoc_new', {'id': calendar.id }) }}"> | ||||
|                                         {{ 'chill_calendar.Add a document'|trans }} | ||||
|                                     </a> | ||||
|                                 </li> | ||||
|                             {% else %} | ||||
|                                 <li> | ||||
|                                     <div class="dropdown"> | ||||
|                                         <button class="btn btn-create dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false"> | ||||
|                                             {{ 'chill_calendar.Add a document'|trans }} | ||||
|                                         </button> | ||||
|                                         <ul class="dropdown-menu"> | ||||
|                                             <li> | ||||
|                                                 <a class="dropdown-item" | ||||
|                                                    href="{{ chill_path_add_return_path('chill_calendar_calendardoc_new', {'id': calendar.id }) }}"> | ||||
|                                                     {{ 'chill_calendar.Upload a document'|trans }} | ||||
|                                                 </a> | ||||
|                                             </li> | ||||
|                                             {% for template in templates %} | ||||
|                                             <li> | ||||
|                                                 <a class="dropdown-item" | ||||
|                                                     href="{{ chill_path_add_return_path('chill_docgenerator_generate_from_template', {'template': template.id, 'entityClassName': 'Chill\\CalendarBundle\\Entity\\Calendar', 'entityId': calendar.id}) }}" | ||||
|                                                 > | ||||
|                                                    {{ template.name|localize_translatable_string }} | ||||
|                                                 </a> | ||||
|                                             </li> | ||||
|                                             {% endfor %} | ||||
|                                         </ul> | ||||
|                                     </div> | ||||
|                                 </li> | ||||
|                             {% endif %} | ||||
|                         {% endif %} | ||||
|                         {% if calendar.activity is null and ( | ||||
|                             (calendar.context == 'accompanying_period' and is_granted('CHILL_ACTIVITY_CREATE', calendar.accompanyingPeriod)) | ||||
|                             or | ||||
|                             (calendar.context == 'person' and is_granted('CHILL_ACTIVITY_CREATE', calendar.person)) | ||||
|                             ) | ||||
|                         %} | ||||
|                             <li> | ||||
|                                 <a class="btn btn-create" | ||||
|                                    href="{{ chill_path_add_return_path('chill_calendar_calendar_to_activity', { 'id': calendar.id }) }}"> | ||||
|                                     {{ 'Transform to activity'|trans }} | ||||
|                                 </a> | ||||
|                             </li> | ||||
|                         {% endif %} | ||||
|  | ||||
|                         {% if (calendar.isInvited(app.user)) %} | ||||
|                             {% set invite = calendar.inviteForUser(app.user) %} | ||||
|                             <li> | ||||
|                                 <div invite-answer data-status="{{ invite.status|e('html_attr') }}" | ||||
|                                      data-calendar-id="{{ calendar.id|e('html_attr') }}"></div> | ||||
|                             </li> | ||||
|                         {% endif %} | ||||
|                         {% if false %} | ||||
|                             <li> | ||||
|                                 <a href="{{ chill_path_add_return_path('chill_calendar_calendar_show', { 'id': calendar.id}) }}" | ||||
|                                    class="btn btn-show "></a> | ||||
|                             </li> | ||||
|                         {% endif %} | ||||
|                         {% if is_granted('CHILL_CALENDAR_CALENDAR_EDIT', calendar) %} | ||||
|                         <li> | ||||
|                             <a href="{{ chill_path_add_return_path('chill_calendar_calendar_edit', { 'id': calendar.id }) }}" | ||||
|                                class="btn btn-update "></a> | ||||
|                         </li> | ||||
|                         {% endif %} | ||||
|                         {% if is_granted('CHILL_CALENDAR_CALENDAR_DELETE', calendar) %} | ||||
|                         <li> | ||||
|                             <a href="{{ chill_path_add_return_path('chill_calendar_calendar_delete', { 'id': calendar.id } ) }}" | ||||
|                                class="btn btn-delete "></a> | ||||
|                         </li> | ||||
|                         {% endif %} | ||||
|                     </ul> | ||||
|  | ||||
|                 </div> | ||||
|  | ||||
|             </div> | ||||
|         {% endfor %} | ||||
|         </div> | ||||
|     {% endif %} | ||||
|  | ||||
|         {% if calendarItems|length < paginator.getTotalItems %} | ||||
|             {{ chill_pagination(paginator) }} | ||||
|         {% endif %} | ||||
|     <div class="item-row separator"> | ||||
|         <ul class="record_actions"> | ||||
|                 {% if is_granted('CHILL_CALENDAR_DOC_EDIT', calendar) %} | ||||
|                     {% if templates|length == 0 %} | ||||
|                         <li> | ||||
|                             <a class="btn btn-create" | ||||
|                                href="{{ chill_path_add_return_path('chill_calendar_calendardoc_new', {'id': calendar.id }) }}"> | ||||
|                                 {{ 'chill_calendar.Add a document'|trans }} | ||||
|                             </a> | ||||
|                         </li> | ||||
|                     {% else %} | ||||
|                         <li> | ||||
|                             <div class="dropdown"> | ||||
|                                 <button class="btn btn-create dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false"> | ||||
|                                     {{ 'chill_calendar.Add a document'|trans }} | ||||
|                                 </button> | ||||
|                                 <ul class="dropdown-menu"> | ||||
|                                     <li> | ||||
|                                         <a class="dropdown-item" | ||||
|                                            href="{{ chill_path_add_return_path('chill_calendar_calendardoc_new', {'id': calendar.id }) }}"> | ||||
|                                             {{ 'chill_calendar.Upload a document'|trans }} | ||||
|                                         </a> | ||||
|                                     </li> | ||||
|                                     {% for template in templates %} | ||||
|                                     <li> | ||||
|                                         <a class="dropdown-item" | ||||
|                                             href="{{ chill_path_add_return_path('chill_docgenerator_generate_from_template', {'template': template.id, 'entityClassName': 'Chill\\CalendarBundle\\Entity\\Calendar', 'entityId': calendar.id}) }}" | ||||
|                                         > | ||||
|                                            {{ template.name|localize_translatable_string }} | ||||
|                                         </a> | ||||
|                                     </li> | ||||
|                                     {% endfor %} | ||||
|                                 </ul> | ||||
|                             </div> | ||||
|                         </li> | ||||
|                     {% endif %} | ||||
|                 {% endif %} | ||||
|             {% if calendar.activity is null and ( | ||||
|                 (calendar.context == 'accompanying_period' and is_granted('CHILL_ACTIVITY_CREATE', calendar.accompanyingPeriod)) | ||||
|                 or | ||||
|                 (calendar.context == 'person' and is_granted('CHILL_ACTIVITY_CREATE', calendar.person)) | ||||
|                 ) | ||||
|             %} | ||||
|                 <li> | ||||
|                     <a class="btn btn-create" | ||||
|                        href="{{ chill_path_add_return_path('chill_calendar_calendar_to_activity', { 'id': calendar.id }) }}"> | ||||
|                         {{ 'Transform to activity'|trans }} | ||||
|                     </a> | ||||
|                 </li> | ||||
|             {% endif %} | ||||
|  | ||||
|             {% if (calendar.isInvited(app.user)) %} | ||||
|                 {% set invite = calendar.inviteForUser(app.user) %} | ||||
|                 <li> | ||||
|                     <div invite-answer data-status="{{ invite.status|e('html_attr') }}" | ||||
|                          data-calendar-id="{{ calendar.id|e('html_attr') }}"></div> | ||||
|                 </li> | ||||
|             {% endif %} | ||||
|             {% if false %} | ||||
|                 <li> | ||||
|                     <a href="{{ chill_path_add_return_path('chill_calendar_calendar_show', { 'id': calendar.id}) }}" | ||||
|                        class="btn btn-show "></a> | ||||
|                 </li> | ||||
|             {% endif %} | ||||
|             {% if is_granted('CHILL_CALENDAR_CALENDAR_EDIT', calendar) %} | ||||
|             <li> | ||||
|                 <a href="{{ chill_path_add_return_path('chill_calendar_calendar_edit', { 'id': calendar.id }) }}" | ||||
|                    class="btn btn-update "></a> | ||||
|             </li> | ||||
|             {% endif %} | ||||
|             {% if is_granted('CHILL_CALENDAR_CALENDAR_DELETE', calendar) %} | ||||
|             <li> | ||||
|                 <a href="{{ chill_path_add_return_path('chill_calendar_calendar_delete', { 'id': calendar.id } ) }}" | ||||
|                    class="btn btn-delete "></a> | ||||
|             </li> | ||||
|             {% endif %} | ||||
|         </ul> | ||||
|  | ||||
|     </div> | ||||
| {% endif %} | ||||
|  | ||||
| </div> | ||||
|  | ||||
|  | ||||
|   | ||||
| @@ -34,7 +34,18 @@ | ||||
|             {% endif %} | ||||
|         </p> | ||||
|     {% else %} | ||||
|         {{ include('@ChillCalendar/Calendar/_list.html.twig', {context: 'accompanying_course'}) }} | ||||
|         {% if calendarItems|length > 0 %} | ||||
|             <div class="flex-table list-records context-accompanyingCourse"> | ||||
|                 {% for calendar in calendarItems %} | ||||
|                     {{ include('@ChillCalendar/Calendar/_list.html.twig', {context: 'accompanying_course'}) }} | ||||
|                 {% endfor %} | ||||
|             </div> | ||||
|  | ||||
|             {% if calendarItems|length < paginator.getTotalItems %} | ||||
|                 {{ chill_pagination(paginator) }} | ||||
|             {% endif %} | ||||
|  | ||||
|         {% endif %} | ||||
|     {% endif %} | ||||
|  | ||||
|     <ul class="record_actions sticky-form-buttons"> | ||||
|   | ||||
| @@ -33,7 +33,17 @@ | ||||
|             {% endif %} | ||||
|         </p> | ||||
|     {% else %} | ||||
|         {{ include ('@ChillCalendar/Calendar/_list.html.twig', {context: 'person'}) }} | ||||
|         {% if calendarItems|length > 0 %} | ||||
|             <div class="flex-table list-records context-person"> | ||||
|                 {% for calendar in calendarItems %} | ||||
|                     {{ include ('@ChillCalendar/Calendar/_list.html.twig', {context: 'person'}) }} | ||||
|                 {% endfor %} | ||||
|             </div> | ||||
|  | ||||
|             {% if calendarItems|length < paginator.getTotalItems %} | ||||
|                 {{ chill_pagination(paginator) }} | ||||
|             {% endif %} | ||||
|         {% endif %} | ||||
|     {% endif %} | ||||
|  | ||||
|     <ul class="record_actions sticky-form-buttons"> | ||||
|   | ||||
| @@ -0,0 +1,40 @@ | ||||
| {% extends "@ChillMain/layout.html.twig" %} | ||||
|  | ||||
| {% set activeRouteKey = 'chill_calendar_invitations_list' %} | ||||
|  | ||||
| {% block title %}{{ 'My invitations list' |trans }}{% endblock title %} | ||||
|  | ||||
| {% block content %} | ||||
|  | ||||
|     <h1>{{ 'invite.list.title'|trans }}</h1> | ||||
|  | ||||
|     {% if invitations|length == 0 %} | ||||
|         <p class="chill-no-data-statement"> | ||||
|             {{ "invite.list.none"|trans }} | ||||
|         </p> | ||||
|     {% else %} | ||||
|         <div class="flex-table list-records"> | ||||
|             {% for invitation in invitations %} | ||||
|                 {% set calendar = invitation.getCalendar %} | ||||
|                 {{ include('@ChillCalendar/Calendar/_list.html.twig', {context: 'user'}) }} | ||||
|             {% endfor %} | ||||
|         </div> | ||||
|  | ||||
|         {% if invitations|length < paginator.getTotalItems %} | ||||
|             {{ chill_pagination(paginator) }} | ||||
|         {% endif %} | ||||
|     {% endif %} | ||||
|  | ||||
| {% endblock %} | ||||
|  | ||||
| {% block js %} | ||||
|     {{ parent() }} | ||||
|     {{ encore_entry_script_tags('mod_answer') }} | ||||
|     {{ encore_entry_script_tags('mod_document_action_buttons_group') }} | ||||
| {% endblock %} | ||||
|  | ||||
| {% block css %} | ||||
|     {{ parent() }} | ||||
|     {{ encore_entry_link_tags('mod_answer') }} | ||||
|     {{ encore_entry_link_tags('mod_document_action_buttons_group') }} | ||||
| {% endblock %} | ||||
| @@ -0,0 +1,292 @@ | ||||
| <?php | ||||
|  | ||||
| declare(strict_types=1); | ||||
|  | ||||
| /* | ||||
|  * Chill is a software for social workers | ||||
|  * | ||||
|  * For the full copyright and license information, please view | ||||
|  * the LICENSE file that was distributed with this source code. | ||||
|  */ | ||||
|  | ||||
| namespace Chill\CalendarBundle\Tests\Controller; | ||||
|  | ||||
| use Chill\CalendarBundle\Controller\MyInvitationsController; | ||||
| use Chill\CalendarBundle\Entity\Calendar; | ||||
| use Chill\CalendarBundle\Entity\Invite; | ||||
| use Chill\CalendarBundle\Repository\InviteRepository; | ||||
| use Chill\DocGeneratorBundle\Repository\DocGeneratorTemplateRepositoryInterface; | ||||
| use Chill\MainBundle\Entity\User; | ||||
| use Chill\MainBundle\Pagination\PaginatorFactory; | ||||
| use Chill\MainBundle\Pagination\PaginatorInterface; | ||||
| use PHPUnit\Framework\TestCase; | ||||
| use Prophecy\PhpUnit\ProphecyTrait; | ||||
| use Symfony\Component\HttpFoundation\Request; | ||||
| use Symfony\Component\HttpFoundation\Response; | ||||
| use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; | ||||
| use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; | ||||
| use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface; | ||||
| use Twig\Environment; | ||||
|  | ||||
| /** | ||||
|  * @internal | ||||
|  * | ||||
|  * @coversNothing | ||||
|  */ | ||||
| final class MyInvitationsControllerTest extends TestCase | ||||
| { | ||||
|     use ProphecyTrait; | ||||
|  | ||||
|     private MyInvitationsController $controller; | ||||
|  | ||||
|     protected function setUp(): void | ||||
|     { | ||||
|         // Create prophecies for dependencies | ||||
|         $inviteRepository = $this->prophesize(InviteRepository::class); | ||||
|         $paginatorFactory = $this->prophesize(PaginatorFactory::class); | ||||
|         $docGeneratorTemplateRepository = $this->prophesize(DocGeneratorTemplateRepositoryInterface::class); | ||||
|  | ||||
|         // Create controller instance | ||||
|         $this->controller = new MyInvitationsController( | ||||
|             $inviteRepository->reveal(), | ||||
|             $paginatorFactory->reveal(), | ||||
|             $docGeneratorTemplateRepository->reveal() | ||||
|         ); | ||||
|  | ||||
|         // Set up necessary services for AbstractController | ||||
|         $authorizationChecker = $this->prophesize(AuthorizationCheckerInterface::class); | ||||
|         $tokenStorage = $this->prophesize(TokenStorageInterface::class); | ||||
|         $twig = $this->prophesize(Environment::class); | ||||
|  | ||||
|         // Use reflection to set the container | ||||
|         $reflection = new \ReflectionClass($this->controller); | ||||
|         $containerProperty = $reflection->getParentClass()->getProperty('container'); | ||||
|         $containerProperty->setAccessible(true); | ||||
|  | ||||
|         // Create a mock container | ||||
|         $container = $this->prophesize(\Psr\Container\ContainerInterface::class); | ||||
|         $container->has('security.authorization_checker')->willReturn(true); | ||||
|         $container->get('security.authorization_checker')->willReturn($authorizationChecker->reveal()); | ||||
|         $container->has('security.token_storage')->willReturn(true); | ||||
|         $container->get('security.token_storage')->willReturn($tokenStorage->reveal()); | ||||
|         $container->has('twig')->willReturn(true); | ||||
|         $container->get('twig')->willReturn($twig->reveal()); | ||||
|  | ||||
|         $containerProperty->setValue($this->controller, $container->reveal()); | ||||
|     } | ||||
|  | ||||
|     public function testMyInvitationsReturnsCorrectAmountOfInvitations(): void | ||||
|     { | ||||
|         // Create test user | ||||
|         $user = new User(); | ||||
|         $user->setUsername('testuser'); | ||||
|  | ||||
|         // Create test invitations | ||||
|         $invite1 = new Invite(); | ||||
|         $invite1->setUser($user); | ||||
|         $invite1->setStatus(Invite::PENDING); | ||||
|  | ||||
|         $invite2 = new Invite(); | ||||
|         $invite2->setUser($user); | ||||
|         $invite2->setStatus(Invite::ACCEPTED); | ||||
|  | ||||
|         $invite3 = new Invite(); | ||||
|         $invite3->setUser($user); | ||||
|         $invite3->setStatus(Invite::DECLINED); | ||||
|  | ||||
|         $allInvitations = [$invite1, $invite2, $invite3]; | ||||
|         $paginatedInvitations = [$invite1, $invite2]; // First page with 2 items per page | ||||
|  | ||||
|         // Set up repository prophecies | ||||
|         $inviteRepository = $this->prophesize(InviteRepository::class); | ||||
|         $inviteRepository->findBy(['user' => $user])->willReturn($allInvitations); | ||||
|         $inviteRepository->findBy( | ||||
|             ['user' => $user], | ||||
|             ['createdAt' => 'DESC'], | ||||
|             2, // items per page | ||||
|             0  // offset | ||||
|         )->willReturn($paginatedInvitations); | ||||
|  | ||||
|         // Set up paginator prophecies | ||||
|         $paginator = $this->prophesize(PaginatorInterface::class); | ||||
|         $paginator->getItemsPerPage()->willReturn(2); | ||||
|         $paginator->getCurrentPageFirstItemNumber()->willReturn(0); | ||||
|  | ||||
|         $paginatorFactory = $this->prophesize(PaginatorFactory::class); | ||||
|         $paginatorFactory->create(3)->willReturn($paginator->reveal()); | ||||
|  | ||||
|         // Set up doc generator repository | ||||
|         $docGeneratorTemplateRepository = $this->prophesize(DocGeneratorTemplateRepositoryInterface::class); | ||||
|         $docGeneratorTemplateRepository->findByEntity(Calendar::class)->willReturn([]); | ||||
|  | ||||
|         // Create controller with mocked dependencies | ||||
|         $controller = new MyInvitationsController( | ||||
|             $inviteRepository->reveal(), | ||||
|             $paginatorFactory->reveal(), | ||||
|             $docGeneratorTemplateRepository->reveal() | ||||
|         ); | ||||
|  | ||||
|         // Set up authorization checker to return true for ROLE_USER | ||||
|         $authorizationChecker = $this->prophesize(AuthorizationCheckerInterface::class); | ||||
|         $authorizationChecker->isGranted('ROLE_USER', null)->willReturn(true); | ||||
|  | ||||
|         // Set up token storage to return user | ||||
|         $token = $this->prophesize(TokenInterface::class); | ||||
|         $token->getUser()->willReturn($user); | ||||
|         $tokenStorage = $this->prophesize(TokenStorageInterface::class); | ||||
|         $tokenStorage->getToken()->willReturn($token->reveal()); | ||||
|  | ||||
|         // Set up twig to return a response | ||||
|         $twig = $this->prophesize(Environment::class); | ||||
|         $twig->render('@ChillCalendar/Invitations/listByUser.html.twig', [ | ||||
|             'invitations' => $paginatedInvitations, | ||||
|             'paginator' => $paginator->reveal(), | ||||
|             'templates' => [], | ||||
|         ])->willReturn('rendered content'); | ||||
|  | ||||
|         // Set up container | ||||
|         $container = $this->prophesize(\Psr\Container\ContainerInterface::class); | ||||
|         $container->has('security.authorization_checker')->willReturn(true); | ||||
|         $container->get('security.authorization_checker')->willReturn($authorizationChecker->reveal()); | ||||
|         $container->has('security.token_storage')->willReturn(true); | ||||
|         $container->get('security.token_storage')->willReturn($tokenStorage->reveal()); | ||||
|         $container->has('twig')->willReturn(true); | ||||
|         $container->get('twig')->willReturn($twig->reveal()); | ||||
|  | ||||
|         // Use reflection to set the container | ||||
|         $reflection = new \ReflectionClass($controller); | ||||
|         $containerProperty = $reflection->getParentClass()->getProperty('container'); | ||||
|         $containerProperty->setAccessible(true); | ||||
|         $containerProperty->setValue($controller, $container->reveal()); | ||||
|  | ||||
|         // Create request | ||||
|         $request = new Request(); | ||||
|  | ||||
|         // Execute the action | ||||
|         $response = $controller->myInvitations($request); | ||||
|  | ||||
|         // Assert that response is successful | ||||
|         self::assertInstanceOf(Response::class, $response); | ||||
|         self::assertSame(200, $response->getStatusCode()); | ||||
|         self::assertSame('rendered content', $response->getContent()); | ||||
|     } | ||||
|  | ||||
|     public function testMyInvitationsPageLoads(): void | ||||
|     { | ||||
|         // Create test user | ||||
|         $user = new User(); | ||||
|         $user->setUsername('testuser'); | ||||
|  | ||||
|         // Set up repository prophecies - no invitations | ||||
|         $inviteRepository = $this->prophesize(InviteRepository::class); | ||||
|         $inviteRepository->findBy(['user' => $user])->willReturn([]); | ||||
|         $inviteRepository->findBy( | ||||
|             ['user' => $user], | ||||
|             ['createdAt' => 'DESC'], | ||||
|             20, // default items per page | ||||
|             0   // offset | ||||
|         )->willReturn([]); | ||||
|  | ||||
|         // Set up paginator prophecies | ||||
|         $paginator = $this->prophesize(PaginatorInterface::class); | ||||
|         $paginator->getItemsPerPage()->willReturn(20); | ||||
|         $paginator->getCurrentPageFirstItemNumber()->willReturn(0); | ||||
|  | ||||
|         $paginatorFactory = $this->prophesize(PaginatorFactory::class); | ||||
|         $paginatorFactory->create(0)->willReturn($paginator->reveal()); | ||||
|  | ||||
|         // Set up doc generator repository | ||||
|         $docGeneratorTemplateRepository = $this->prophesize(DocGeneratorTemplateRepositoryInterface::class); | ||||
|         $docGeneratorTemplateRepository->findByEntity(Calendar::class)->willReturn([]); | ||||
|  | ||||
|         // Create controller with mocked dependencies | ||||
|         $controller = new MyInvitationsController( | ||||
|             $inviteRepository->reveal(), | ||||
|             $paginatorFactory->reveal(), | ||||
|             $docGeneratorTemplateRepository->reveal() | ||||
|         ); | ||||
|  | ||||
|         // Set up authorization checker to return true for ROLE_USER | ||||
|         $authorizationChecker = $this->prophesize(AuthorizationCheckerInterface::class); | ||||
|         $authorizationChecker->isGranted('ROLE_USER', null)->willReturn(true); | ||||
|  | ||||
|         // Set up token storage to return user | ||||
|         $token = $this->prophesize(TokenInterface::class); | ||||
|         $token->getUser()->willReturn($user); | ||||
|         $tokenStorage = $this->prophesize(TokenStorageInterface::class); | ||||
|         $tokenStorage->getToken()->willReturn($token->reveal()); | ||||
|  | ||||
|         // Set up twig to return a response | ||||
|         $twig = $this->prophesize(Environment::class); | ||||
|         $twig->render('@ChillCalendar/Invitations/listByUser.html.twig', [ | ||||
|             'invitations' => [], | ||||
|             'paginator' => $paginator->reveal(), | ||||
|             'templates' => [], | ||||
|         ])->willReturn('empty page content'); | ||||
|  | ||||
|         // Set up container | ||||
|         $container = $this->prophesize(\Psr\Container\ContainerInterface::class); | ||||
|         $container->has('security.authorization_checker')->willReturn(true); | ||||
|         $container->get('security.authorization_checker')->willReturn($authorizationChecker->reveal()); | ||||
|         $container->has('security.token_storage')->willReturn(true); | ||||
|         $container->get('security.token_storage')->willReturn($tokenStorage->reveal()); | ||||
|         $container->has('twig')->willReturn(true); | ||||
|         $container->get('twig')->willReturn($twig->reveal()); | ||||
|  | ||||
|         // Use reflection to set the container | ||||
|         $reflection = new \ReflectionClass($controller); | ||||
|         $containerProperty = $reflection->getParentClass()->getProperty('container'); | ||||
|         $containerProperty->setAccessible(true); | ||||
|         $containerProperty->setValue($controller, $container->reveal()); | ||||
|  | ||||
|         // Create request | ||||
|         $request = new Request(); | ||||
|  | ||||
|         // Execute the action | ||||
|         $response = $controller->myInvitations($request); | ||||
|  | ||||
|         // Assert that page loads successfully | ||||
|         self::assertInstanceOf(Response::class, $response); | ||||
|         self::assertSame(200, $response->getStatusCode()); | ||||
|         self::assertSame('empty page content', $response->getContent()); | ||||
|     } | ||||
|  | ||||
|     public function testMyInvitationsRequiresAuthentication(): void | ||||
|     { | ||||
|         // Create controller with minimal dependencies | ||||
|         $inviteRepository = $this->prophesize(InviteRepository::class); | ||||
|         $paginatorFactory = $this->prophesize(PaginatorFactory::class); | ||||
|         $docGeneratorTemplateRepository = $this->prophesize(DocGeneratorTemplateRepositoryInterface::class); | ||||
|  | ||||
|         $controller = new MyInvitationsController( | ||||
|             $inviteRepository->reveal(), | ||||
|             $paginatorFactory->reveal(), | ||||
|             $docGeneratorTemplateRepository->reveal() | ||||
|         ); | ||||
|  | ||||
|         // Set up authorization checker to return false for ROLE_USER | ||||
|         $authorizationChecker = $this->prophesize(AuthorizationCheckerInterface::class); | ||||
|         $authorizationChecker->isGranted('ROLE_USER')->willReturn(false); | ||||
|         $authorizationChecker->isGranted('ROLE_USER', null)->willReturn(false); | ||||
|  | ||||
|         // Set up container | ||||
|         $container = $this->prophesize(\Psr\Container\ContainerInterface::class); | ||||
|         $container->has('security.authorization_checker')->willReturn(true); | ||||
|         $container->get('security.authorization_checker')->willReturn($authorizationChecker->reveal()); | ||||
|  | ||||
|         // Use reflection to set the container | ||||
|         $reflection = new \ReflectionClass($controller); | ||||
|         $containerProperty = $reflection->getParentClass()->getProperty('container'); | ||||
|         $containerProperty->setAccessible(true); | ||||
|         $containerProperty->setValue($controller, $container->reveal()); | ||||
|  | ||||
|         // Create request | ||||
|         $request = new Request(); | ||||
|  | ||||
|         // Expect AccessDeniedException | ||||
|         $this->expectException(\Symfony\Component\Security\Core\Exception\AccessDeniedException::class); | ||||
|  | ||||
|         // Execute the action | ||||
|         $controller->myInvitations($request); | ||||
|     } | ||||
| } | ||||
| @@ -86,6 +86,9 @@ invite: | ||||
|     declined: Refusé | ||||
|     pending: En attente | ||||
|     tentative: Accepté provisoirement | ||||
|     list: | ||||
|         none: Il n'y aucun invitation | ||||
|         title: Mes invitations | ||||
|  | ||||
| # exports | ||||
| Exports of calendar: Exports des rendez-vous | ||||
|   | ||||
| @@ -20,4 +20,9 @@ use Doctrine\Persistence\ObjectRepository; | ||||
| interface DocGeneratorTemplateRepositoryInterface extends ObjectRepository | ||||
| { | ||||
|     public function countByEntity(string $entity): int; | ||||
|  | ||||
|     /** | ||||
|      * @return array|DocGeneratorTemplate[] | ||||
|      */ | ||||
|     public function findByEntity(string $entity, ?int $start = 0, ?int $limit = 50): array; | ||||
| } | ||||
|   | ||||
| @@ -17,7 +17,7 @@ use Symfony\Component\Routing\RouterInterface; | ||||
| /** | ||||
|  * Create paginator instances. | ||||
|  */ | ||||
| final readonly class PaginatorFactory implements PaginatorFactoryInterface | ||||
| class PaginatorFactory implements PaginatorFactoryInterface | ||||
| { | ||||
|     final public const DEFAULT_CURRENT_PAGE_KEY = 'page'; | ||||
|  | ||||
| @@ -29,16 +29,16 @@ final readonly class PaginatorFactory implements PaginatorFactoryInterface | ||||
|         /** | ||||
|          * the request stack. | ||||
|          */ | ||||
|         private RequestStack $requestStack, | ||||
|         private readonly RequestStack $requestStack, | ||||
|         /** | ||||
|          * the router and generator for url. | ||||
|          */ | ||||
|         private RouterInterface $router, | ||||
|         private readonly RouterInterface $router, | ||||
|         /** | ||||
|          * the default item per page. This may be overriden by | ||||
|          * the request or inside the paginator. | ||||
|          */ | ||||
|         private int $itemPerPage = 20, | ||||
|         private readonly int $itemPerPage = 20, | ||||
|     ) {} | ||||
|  | ||||
|     /** | ||||
|   | ||||
		Reference in New Issue
	
	Block a user