Dev 4.8.0 #15

Merged
th.guenther merged 11 commits from dev-4.8.0 into main 2026-09-04 09:29:57 +02:00
51 changed files with 30702 additions and 87 deletions
Showing only changes of commit 4bb64b0053 - Show all commits
+29010
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -23,7 +23,7 @@ class UserDetailGetController extends CommonController
return response()->json([ return response()->json([
'user' => $userData, 'user' => $userData,
'isOwnUser' => auth()->id() === $user->id, 'isOwnUser' => currentUser()?->id === $user->id,
'isLvTenant' => $this->tenant->slug === 'lv', 'isLvTenant' => $this->tenant->slug === 'lv',
'userRoles' => UserRole::all()->map(fn($role) => ['slug' => $role->slug, 'name' => $role->name]), 'userRoles' => UserRole::all()->map(fn($role) => ['slug' => $role->slug, 'name' => $role->name]),
'localGroups' => $this->adminTenants->getActiveLocalGroups()->map(fn($t) => ['slug' => $t->slug, 'name' => $t->name]), 'localGroups' => $this->adminTenants->getActiveLocalGroups()->map(fn($t) => ['slug' => $t->slug, 'name' => $t->name]),
@@ -16,7 +16,7 @@ class UserToggleActiveController extends CommonController
$action = new ToggleUserActiveAction(new ToggleUserActiveRequest( $action = new ToggleUserActiveAction(new ToggleUserActiveRequest(
user: $user, user: $user,
currentUserId: auth()->id(), currentUserId: currentUser()?->id,
)); ));
$response = $action->execute(); $response = $action->execute();
@@ -17,7 +17,7 @@ class UserUpdateController extends CommonController
$action = new UpdateUserAction(new UpdateUserRequest( $action = new UpdateUserAction(new UpdateUserRequest(
user: $user, user: $user,
data: $request->all(), data: $request->all(),
isOwnUser: auth()->id() === $user->id, isOwnUser: currentUser()?->id === $user->id,
isLvTenant: $this->tenant->slug === 'lv', isLvTenant: $this->tenant->slug === 'lv',
)); ));
@@ -25,7 +25,7 @@ class CreateEstimateAction {
if ($this->request->estimateId === 0) { if ($this->request->estimateId === 0) {
$estimate = CostUnitEstimate::create(array_merge([ $estimate = CostUnitEstimate::create(array_merge([
'tenant' => app('tenant')->slug, 'tenant' => currentTenant()->slug,
'cost_unit_id' => $this->request->costUnit->id, 'cost_unit_id' => $this->request->costUnit->id,
'type' => $this->request->estimateType, 'type' => $this->request->estimateType,
'description' => $this->request->description, 'description' => $this->request->description,
@@ -33,7 +33,7 @@ class CreateEstimateAction {
} else { } else {
$estimate = CostUnitEstimate::find($this->request->estimateId); $estimate = CostUnitEstimate::find($this->request->estimateId);
$estimate->update(array_merge([ $estimate->update(array_merge([
'tenant' => app('tenant')->slug, 'tenant' => currentTenant()->slug,
'cost_unit_id' => $this->request->costUnit->id, 'cost_unit_id' => $this->request->costUnit->id,
'type' => $this->request->estimateType, 'type' => $this->request->estimateType,
'description' => $this->request->description, 'description' => $this->request->description,
@@ -15,7 +15,7 @@ class CreateCostUnitCommand {
$response = new CreateCostUnitResponse(); $response = new CreateCostUnitResponse();
$costUnit = CostUnit::create([ $costUnit = CostUnit::create([
'name' => $this->request->name, 'name' => $this->request->name,
'tenant' => app('tenant')->slug, 'tenant' => currentTenant()->slug,
'type' => $this->request->type, 'type' => $this->request->type,
'billing_deadline' => $this->request->billingDeadline, 'billing_deadline' => $this->request->billingDeadline,
'distance_allowance' => $this->request->distanceAllowance->getAmount(), 'distance_allowance' => $this->request->distanceAllowance->getAmount(),
@@ -13,7 +13,7 @@ class PersonalDataController extends CommonController
return redirect()->intended('/login'); return redirect()->intended('/login');
} }
$user = auth()->user(); $user = currentUser();
$data = $this->users->getPersonalData($user); $data = $this->users->getPersonalData($user);
$inertiaProvider = new InertiaProvider('Dashboard/PersonalData', [ $inertiaProvider = new InertiaProvider('Dashboard/PersonalData', [
@@ -12,7 +12,7 @@ class StorePersonalDataController extends CommonController
{ {
public function __invoke(Request $request): JsonResponse public function __invoke(Request $request): JsonResponse
{ {
$user = auth()->user(); $user = currentUser();
$actionRequest = new UpdatePersonalDataRequest( $actionRequest = new UpdatePersonalDataRequest(
user: $user, user: $user,
@@ -28,7 +28,7 @@ class CreateEventCommand {
} }
$tenant = app('tenant'); $tenant = currentTenant();
// Anlage als Ganzes: der Event-Teil der Rechnungsnummer wird unter der Sperre vergeben und muss // Anlage als Ganzes: der Event-Teil der Rechnungsnummer wird unter der Sperre vergeben und muss
// im selben Zug geschrieben werden, sonst könnten zwei gleichzeitige Anlagen denselben erhalten. // im selben Zug geschrieben werden, sonst könnten zwei gleichzeitige Anlagen denselben erhalten.
@@ -91,12 +91,12 @@ class CreateEventCommand {
]); ]);
} }
if (app('tenant')->slug === 'lv') { if (currentTenant()->slug === 'lv') {
foreach(Tenant::where(['is_active_local_group' => true])->get() as $tenant) { foreach(Tenant::where(['is_active_local_group' => true])->get() as $tenant) {
EventLocalGroups::create(['event_id' => $event->id, 'local_group_id' => $tenant->id]); EventLocalGroups::create(['event_id' => $event->id, 'local_group_id' => $tenant->id]);
} }
} else { } else {
EventLocalGroups::create(['event_id' => $event->id, 'local_group_id' => app('tenant')->id]); EventLocalGroups::create(['event_id' => $event->id, 'local_group_id' => currentTenant()->id]);
} }
@@ -13,7 +13,7 @@ class GenerateIcalCommand
$participant = $this->request->participant; $participant = $this->request->participant;
$event = $participant->event; $event = $participant->event;
$uid = $participant->identifier . '@' . app('tenant')->slug; $uid = $participant->identifier . '@' . currentTenant()->slug;
$dtStart = $event->start_date->format('Ymd'); $dtStart = $event->start_date->format('Ymd');
$dtEnd = $event->end_date->copy()->addDay()->format('Ymd'); $dtEnd = $event->end_date->copy()->addDay()->format('Ymd');
$now = now()->format('Ymd\THis\Z'); $now = now()->format('Ymd\THis\Z');
@@ -24,7 +24,7 @@ class GenerateIcalCommand
$icalContent = implode("\r\n", [ $icalContent = implode("\r\n", [
'BEGIN:VCALENDAR', 'BEGIN:VCALENDAR',
'VERSION:2.0', 'VERSION:2.0',
'PRODID:-//' . app('tenant')->name . '//Veranstaltungskalender//DE', 'PRODID:-//' . currentTenant()->name . '//Veranstaltungskalender//DE',
'CALSCALE:GREGORIAN', 'CALSCALE:GREGORIAN',
'METHOD:PUBLISH', 'METHOD:PUBLISH',
'BEGIN:VEVENT', 'BEGIN:VEVENT',
@@ -21,11 +21,11 @@ class GenerateIcalForDeadlineCommand {
$icalContent = implode("\r\n", [ $icalContent = implode("\r\n", [
'BEGIN:VCALENDAR', 'BEGIN:VCALENDAR',
'VERSION:2.0', 'VERSION:2.0',
'PRODID:-//' . app('tenant')->name . '//Veranstaltungskalender//DE', 'PRODID:-//' . currentTenant()->name . '//Veranstaltungskalender//DE',
'CALSCALE:GREGORIAN', 'CALSCALE:GREGORIAN',
'METHOD:PUBLISH', 'METHOD:PUBLISH',
'BEGIN:VEVENT', 'BEGIN:VEVENT',
'UID:payment-deadline-' . $event->identifier . '@' . app('tenant')->slug, 'UID:payment-deadline-' . $event->identifier . '@' . currentTenant()->slug,
'DTSTAMP:' . $now, 'DTSTAMP:' . $now,
'DTSTART;VALUE=DATE:' . $dtDate, 'DTSTART;VALUE=DATE:' . $dtDate,
'DTEND;VALUE=DATE:' . $dtDate, 'DTEND;VALUE=DATE:' . $dtDate,
@@ -18,7 +18,7 @@ class SetParticipationFeesCommand {
$this->cleanBefore(); $this->cleanBefore();
$this->request->event->participationFee1()->associate(EventParticipationFee::create([ $this->request->event->participationFee1()->associate(EventParticipationFee::create([
'tenant' => app('tenant')->slug, 'tenant' => currentTenant()->slug,
'type' => $this->request->participationFeeFirst['type'], 'type' => $this->request->participationFeeFirst['type'],
'name' => $this->request->participationFeeFirst['name'], 'name' => $this->request->participationFeeFirst['name'],
'description' => $this->request->participationFeeFirst['description'], 'description' => $this->request->participationFeeFirst['description'],
@@ -29,7 +29,7 @@ class SetParticipationFeesCommand {
if ($this->request->participationFeeSecond !== null) { if ($this->request->participationFeeSecond !== null) {
$this->request->event->participationFee2()->associate(EventParticipationFee::create([ $this->request->event->participationFee2()->associate(EventParticipationFee::create([
'tenant' => app('tenant')->slug, 'tenant' => currentTenant()->slug,
'type' => $this->request->participationFeeSecond['type'], 'type' => $this->request->participationFeeSecond['type'],
'name' => $this->request->participationFeeSecond['name'], 'name' => $this->request->participationFeeSecond['name'],
'description' => $this->request->participationFeeSecond['description'], 'description' => $this->request->participationFeeSecond['description'],
@@ -41,7 +41,7 @@ class SetParticipationFeesCommand {
if ($this->request->participationFeeThird !== null) { if ($this->request->participationFeeThird !== null) {
$this->request->event->participationFee3()->associate(EventParticipationFee::create([ $this->request->event->participationFee3()->associate(EventParticipationFee::create([
'tenant' => app('tenant')->slug, 'tenant' => currentTenant()->slug,
'type' => $this->request->participationFeeThird['type'], 'type' => $this->request->participationFeeThird['type'],
'name' => $this->request->participationFeeThird['name'], 'name' => $this->request->participationFeeThird['name'],
'description' => $this->request->participationFeeThird['description'], 'description' => $this->request->participationFeeThird['description'],
@@ -53,7 +53,7 @@ class SetParticipationFeesCommand {
if ($this->request->participationFeeFourth !== null) { if ($this->request->participationFeeFourth !== null) {
$this->request->event->participationFee4()->associate(EventParticipationFee::create([ $this->request->event->participationFee4()->associate(EventParticipationFee::create([
'tenant' => app('tenant')->slug, 'tenant' => currentTenant()->slug,
'type' => $this->request->participationFeeFourth['type'], 'type' => $this->request->participationFeeFourth['type'],
'name' => $this->request->participationFeeFourth['name'], 'name' => $this->request->participationFeeFourth['name'],
'description' => $this->request->participationFeeFourth['description'], 'description' => $this->request->participationFeeFourth['description'],
@@ -21,7 +21,7 @@ use Illuminate\Http\Request;
class CreateController extends CommonController { class CreateController extends CommonController {
public function __invoke() { public function __invoke() {
return new InertiaProvider('Event/Create', [ return new InertiaProvider('Event/Create', [
'emailAddress' => auth()->user()->email, 'emailAddress' => currentUserOrFail()->email,
'eventAccount' => $this->tenant->account_name, 'eventAccount' => $this->tenant->account_name,
'eventIban' => $this->tenant->account_iban, 'eventIban' => $this->tenant->account_iban,
'eventPayPerDay' => $this->tenant->slug === 'lv' ? true : false, 'eventPayPerDay' => $this->tenant->slug === 'lv' ? true : false,
@@ -38,7 +38,7 @@ class SendController extends CommonController
} }
} }
$user = auth()->user(); $user = currentUser();
$reportSubject = sprintf('Sendebericht für Nachricht mit Betreff "%s"', $subject); $reportSubject = sprintf('Sendebericht für Nachricht mit Betreff "%s"', $subject);
Mail::to($user->email)->send(new ManualMailsReportMail( Mail::to($user->email)->send(new ManualMailsReportMail(
@@ -35,8 +35,9 @@ class SignupController extends CommonController {
'lastname' => '', 'lastname' => '',
]; ];
if (auth()->check()) { $currentUser = currentUser();
$user = new UserResource(auth()->user())->toArray($request); if ($currentUser !== null) {
$user = new UserResource($currentUser)->toArray($request);
$participantData = [ $participantData = [
'id' => $user['id'], 'id' => $user['id'],
@@ -22,7 +22,7 @@ class ChangeStatusCommand {
switch ($this->request->status) { switch ($this->request->status) {
case InvoiceStatus::INVOICE_STATUS_APPROVED: case InvoiceStatus::INVOICE_STATUS_APPROVED:
$this->request->invoice->status = InvoiceStatus::INVOICE_STATUS_APPROVED; $this->request->invoice->status = InvoiceStatus::INVOICE_STATUS_APPROVED;
$this->request->invoice->approved_by = auth()->user()->id; $this->request->invoice->approved_by = currentUserOrFail()->id;
$this->request->invoice->approved_at = now(); $this->request->invoice->approved_at = now();
if ($this->request->invoice->contact_email !== null) { if ($this->request->invoice->contact_email !== null) {
@@ -35,7 +35,7 @@ class ChangeStatusCommand {
case InvoiceStatus::INVOICE_STATUS_DENIED: case InvoiceStatus::INVOICE_STATUS_DENIED:
$this->request->invoice->status = InvoiceStatus::INVOICE_STATUS_DENIED; $this->request->invoice->status = InvoiceStatus::INVOICE_STATUS_DENIED;
$this->request->invoice->denied_by = auth()->user()->id; $this->request->invoice->denied_by = currentUserOrFail()->id;
$this->request->invoice->denied_at = now(); $this->request->invoice->denied_at = now();
$this->request->invoice->denied_reason = $this->request->comment; $this->request->invoice->denied_reason = $this->request->comment;
if ($this->request->invoice->contact_email !== null) { if ($this->request->invoice->contact_email !== null) {
@@ -24,7 +24,7 @@ class CreateInvoiceCommand {
} }
$invoice = Invoice::create([ $invoice = Invoice::create([
'tenant' => app('tenant')->slug, 'tenant' => currentTenant()->slug,
'cost_unit_id' => $this->request->costUnit->id, 'cost_unit_id' => $this->request->costUnit->id,
'invoice_number' => $this->generateInvoiceNumber(), 'invoice_number' => $this->generateInvoiceNumber(),
'status' => InvoiceStatus::INVOICE_STATUS_NEW, 'status' => InvoiceStatus::INVOICE_STATUS_NEW,
@@ -61,7 +61,7 @@ class CreateInvoiceCommand {
} }
if ($this->request->costUnit->mail_on_new) { if ($this->request->costUnit->mail_on_new) {
$recipients = [app('tenant')->email_finance]; $recipients = [currentTenant()->email_finance];
foreach ($this->request->costUnit->treasurers()->get() as $treasurer) { foreach ($this->request->costUnit->treasurers()->get() as $treasurer) {
if (!in_array($treasurer->email, $recipients)) { if (!in_array($treasurer->email, $recipients)) {
@@ -83,7 +83,7 @@ class CreateInvoiceCommand {
private function generateInvoiceNumber() : string { private function generateInvoiceNumber() : string {
$lastInvoiceNumber = Invoice::query() $lastInvoiceNumber = Invoice::query()
->where('tenant', app('tenant')->slug) ->where('tenant', currentTenant()->slug)
->whereYear('created_at', date('Y')) ->whereYear('created_at', date('Y'))
->count(); ->count();
@@ -19,7 +19,7 @@ class UploadInvoiceCommand {
$uploadDir = sprintf( $uploadDir = sprintf(
'%1$s%2$s/%3$s', '%1$s%2$s/%3$s',
WebDavProvider::INVOICE_PREFIX, WebDavProvider::INVOICE_PREFIX,
app('tenant')->url, currentTenant()->url,
$this->request->invoice->costUnit()->first()->name $this->request->invoice->costUnit()->first()->name
); );
@@ -35,7 +35,7 @@ class CreateParticipantInvoiceCommand
$this->participant = $request->participant; $this->participant = $request->participant;
$this->event = $request->participant->event; $this->event = $request->participant->event;
// Über die Relation und nicht über app('tenant'): die Rechnung hängt an der Veranstaltung, // Über die Relation und nicht über currentTenant(): die Rechnung hängt an der Veranstaltung,
// nicht am gerade aktiven Mandanten. `$event->tenant` liefert das Slug-Attribut, nicht die // nicht am gerade aktiven Mandanten. `$event->tenant` liefert das Slug-Attribut, nicht die
// Relation -- deshalb der ausdrückliche Aufruf. // Relation -- deshalb der ausdrückliche Aufruf.
$this->sender = $this->event->tenant()->first(); $this->sender = $this->event->tenant()->first();
@@ -141,7 +141,7 @@ class AcceptRefundCommand
* Die Kostenstelle der Veranstaltung. * Die Kostenstelle der Veranstaltung.
* *
* Ohne Zugriffsprüfung, weil hier niemand angemeldet ist -- der Teili bestätigt über seinen Token. * Ohne Zugriffsprüfung, weil hier niemand angemeldet ist -- der Teili bestätigt über seinen Token.
* Der Repository-Check greift sonst auf `auth()->user()->id` zu und liefe in einen Fehler. * Der Repository-Check greift sonst auf `currentUserOrFail()->id` zu und liefe in einen Fehler.
* *
* Bewusst ohne Prüfung auf `allow_new`/`archived`: Eine Erstattung fällt oft erst nach dem Ende der * Bewusst ohne Prüfung auf `allow_new`/`archived`: Eine Erstattung fällt oft erst nach dem Ende der
* Veranstaltung an, wenn die Kostenstelle längst geschlossen ist. Sie gehört trotzdem dorthin -- und * Veranstaltung an, wenn die Kostenstelle längst geschlossen ist. Sie gehört trotzdem dorthin -- und
@@ -63,7 +63,7 @@ class ReleaseRefundCommand
'retained_amount' => $this->request->retainedAmount(), 'retained_amount' => $this->request->retainedAmount(),
'retention_reason' => $this->retentionReason(), 'retention_reason' => $this->retentionReason(),
'retention_reason_note' => $this->retentionReasonNote(), 'retention_reason_note' => $this->retentionReasonNote(),
'released_by' => auth()->id(), 'released_by' => currentUser()?->id,
'released_at' => now(), 'released_at' => now(),
]); ]);
@@ -101,7 +101,7 @@ class ReleaseRefundCommand
accountIban: (string) $this->request->accountIban, accountIban: (string) $this->request->accountIban,
// Niemand kreuzt hier eine Erklärung an; wer die Angaben aufgenommen hat, hält `captured_by` // Niemand kreuzt hier eine Erklärung an; wer die Angaben aufgenommen hat, hält `captured_by`
// fest, und der Beleg weist es aus. // fest, und der Beleg weist es aus.
capturedBy: auth()->id(), capturedBy: currentUser()?->id,
))->execute(); ))->execute();
if (!$acceptResponse->success) { if (!$acceptResponse->success) {
@@ -23,7 +23,7 @@ use Illuminate\Http\Request;
class EmailVerificationController extends CommonController class EmailVerificationController extends CommonController
{ {
public function verifyEmailForm(Request $request) { public function verifyEmailForm(Request $request) {
$inertiaProvider = new InertiaProvider('UserManagement/VerifyEmail', ['appName' => app('tenant')->name]); $inertiaProvider = new InertiaProvider('UserManagement/VerifyEmail', ['appName' => currentTenant()->name]);
return $inertiaProvider->render(); return $inertiaProvider->render();
} }
@@ -17,7 +17,7 @@ class LoginController extends CommonController {
} }
$inertiaProvider = new InertiaProvider('UserManagement/Login', ['errors' => $errors, 'appName' => app('tenant')->name]); $inertiaProvider = new InertiaProvider('UserManagement/Login', ['errors' => $errors, 'appName' => currentTenant()->name]);
return $inertiaProvider->render(); return $inertiaProvider->render();
} }
@@ -45,8 +45,8 @@ class LoginController extends CommonController {
]); ]);
} }
$user = Auth::user(); $user = currentUserOrFail();
$tenant = app('tenant'); $tenant = currentTenant();
// Auf "lv" darf sich grundsätzlich jeder aktive Nutzer einloggen. // Auf "lv" darf sich grundsätzlich jeder aktive Nutzer einloggen.
// Auf Sub-Tenants gilt: // Auf Sub-Tenants gilt:
@@ -13,7 +13,7 @@ class ProfileController extends CommonController
return redirect()->intended('/login'); return redirect()->intended('/login');
} }
$user = auth()->user(); $user = currentUser();
$inertiaProvider = new InertiaProvider('UserManagement/Profile', [ $inertiaProvider = new InertiaProvider('UserManagement/Profile', [
'username' => $user->username, 'username' => $user->username,
@@ -26,8 +26,8 @@ class RegistrationController extends CommonController {
$inertiaProvider = new InertiaProvider('UserManagement/Registration', [ $inertiaProvider = new InertiaProvider('UserManagement/Registration', [
'errors' => $errors, 'errors' => $errors,
'appName' => app('tenant')->name, 'appName' => currentTenant()->name,
'tenant' => app('tenant'), 'tenant' => currentTenant(),
]); ]);
return $inertiaProvider->render(); return $inertiaProvider->render();
} }
@@ -46,7 +46,7 @@ class RegistrationController extends CommonController {
$userRoleMain = UserRole::USER_ROLE_USER; $userRoleMain = UserRole::USER_ROLE_USER;
$userRoleLocalGroup = UserRole::USER_ROLE_USER; $userRoleLocalGroup = UserRole::USER_ROLE_USER;
$localGroup = app('tenant')->slug === 'lv' ? $request->get('localGroup') : app('tenant')->slug; $localGroup = currentTenant()->slug === 'lv' ? $request->get('localGroup') : currentTenant()->slug;
$registrationRequest = new UserRegistrationRequest( $registrationRequest = new UserRegistrationRequest(
@@ -7,6 +7,7 @@ use App\Domains\UserManagement\Actions\UserChangePassword\UserChangePasswordRequ
use App\Scopes\CommonController; use App\Scopes\CommonController;
use Illuminate\Http\JsonResponse; use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
class StoreProfileController extends CommonController class StoreProfileController extends CommonController
{ {
@@ -27,11 +28,11 @@ class StoreProfileController extends CommonController
return response()->json(['success' => false, 'message' => 'Die Passwörter stimmen nicht überein.'], 422); return response()->json(['success' => false, 'message' => 'Die Passwörter stimmen nicht überein.'], 422);
} }
$actionRequest = new UserChangePasswordRequest(auth()->user(), $password); $actionRequest = new UserChangePasswordRequest(currentUserOrFail(), $password);
$command = new UserChangePasswordCommand($actionRequest); $command = new UserChangePasswordCommand($actionRequest);
$command->execute(); $command->execute();
auth()->logout(); Auth::logout();
return response()->json(['success' => true, 'message' => 'Dein Passwort wurde erfolgreich geändert.']); return response()->json(['success' => true, 'message' => 'Dein Passwort wurde erfolgreich geändert.']);
} }
} }
@@ -7,7 +7,7 @@ use App\Providers\InertiaProvider;
class TestRenderInertiaProvider class TestRenderInertiaProvider
{ {
public function index() { public function index() {
$inertiaProvider = new InertiaProvider('Invoice/CreateInvoice', ['appName' => app('tenant')->name]); $inertiaProvider = new InertiaProvider('Invoice/CreateInvoice', ['appName' => currentTenant()->name]);
return $inertiaProvider->render(); return $inertiaProvider->render();
} }
} }
+1 -1
View File
@@ -10,7 +10,7 @@ class AdminRoleMiddleware
{ {
public function handle($request, Closure $next) public function handle($request, Closure $next)
{ {
if (!auth()->check()) { if (currentUser() === null) {
return redirect('/login')->with('message', 'Du musst eingeloggt sein.'); return redirect('/login')->with('message', 'Du musst eingeloggt sein.');
} }
+1 -1
View File
@@ -8,7 +8,7 @@ class LvOnlyMiddleware
{ {
public function handle($request, Closure $next) public function handle($request, Closure $next)
{ {
if (app('tenant')->slug !== 'lv') { if (currentTenant()->slug !== 'lv') {
return redirect('/admin')->with('message', 'Diese Funktion ist nur auf LV-Ebene verfügbar.'); return redirect('/admin')->with('message', 'Diese Funktion ist nur auf LV-Ebene verfügbar.');
} }
+1 -1
View File
@@ -15,7 +15,7 @@ class MainAdminRoleMiddleware
{ {
public function handle($request, Closure $next) public function handle($request, Closure $next)
{ {
if (!auth()->check()) { if (currentUser() === null) {
return redirect('/login')->with('message', 'Du musst eingeloggt sein.'); return redirect('/login')->with('message', 'Du musst eingeloggt sein.');
} }
+1 -1
View File
@@ -169,7 +169,7 @@ class Event extends InstancedModel
public function paymentMethods() : BelongsToMany { public function paymentMethods() : BelongsToMany {
// Pivot verknüpft über den Slug (payment_methods.slug), nicht über die numerische id // Pivot verknüpft über den Slug (payment_methods.slug), nicht über die numerische id
// von available_payment_methods -- die tenant-spezifische Instanz wird dadurch implizit // von available_payment_methods -- die tenant-spezifische Instanz wird dadurch implizit
// über den globalen SiteScope von AvailablePaymentMethod (gefiltert auf app('tenant')) aufgelöst. // über den globalen SiteScope von AvailablePaymentMethod (gefiltert auf currentTenant()) aufgelöst.
return $this->belongsToMany(AvailablePaymentMethod::class, 'event_payment_methods', 'event_id', 'slug', 'id', 'slug') return $this->belongsToMany(AvailablePaymentMethod::class, 'event_payment_methods', 'event_id', 'slug', 'id', 'slug')
->using(EventPaymentMethods::class) ->using(EventPaymentMethods::class)
->withPivot('configuration') ->withPivot('configuration')
+1 -1
View File
@@ -50,7 +50,7 @@ class Tenant extends CommonModel
} }
public static function getTempDirectory() : string { public static function getTempDirectory() : string {
return app('tenant')->slug . '/temp-data/'; return currentTenant()->slug . '/temp-data/';
} }
/** /**
+3 -3
View File
@@ -2,7 +2,7 @@
namespace App\Models; namespace App\Models;
use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Foundation\Auth\User as Authenticatable; use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable; use Illuminate\Notifications\Notifiable;
@@ -115,10 +115,10 @@ class User extends Authenticatable
} }
public function localGroup() : Tenant { public function localGroup() : Tenant {
return $this->belongsTo(Tenant::class, 'local_group', 'slug')->first(); return $this->belongsTo(Tenant::class, 'local_group', 'slug')->firstOrFail();
} }
public function costUnits() public function costUnits() : BelongsToMany
{ {
return $this->belongsToMany(CostUnit::class, 'cost_unit_treasurers', 'user_id', 'cost_unit_id') return $this->belongsToMany(CostUnit::class, 'cost_unit_treasurers', 'user_id', 'cost_unit_id')
->withTimestamps(); ->withTimestamps();
+6 -6
View File
@@ -7,12 +7,12 @@ use App\Models\User;
class AuthCheckProvider { class AuthCheckProvider {
public function checkLoggedIn() : bool { public function checkLoggedIn() : bool {
if (!auth()->check()) { $user = currentUser();
if ($user === null) {
return false; return false;
} }
$user = auth()->user(); $tenant = currentTenant();
$tenant = app('tenant');
if ($tenant->slug === 'lv') { if ($tenant->slug === 'lv') {
return $user->active; return $user->active;
} }
@@ -29,9 +29,9 @@ class AuthCheckProvider {
return null; return null;
} }
$user = auth()->user(); $user = currentUserOrFail();
if (app('tenant')->slug === 'lv') { if (currentTenant()->slug === 'lv') {
return $user->user_role_main; return $user->user_role_main;
} }
@@ -50,7 +50,7 @@ class AuthCheckProvider {
* Diese Rolle hebt das lokale Rechtesystem für alle Sub-Tenants auf. * Diese Rolle hebt das lokale Rechtesystem für alle Sub-Tenants auf.
*/ */
public function isMainAdministrator(?User $user = null) : bool { public function isMainAdministrator(?User $user = null) : bool {
$user ??= auth()->user(); $user ??= currentUser();
return $user !== null return $user !== null
&& $user->user_role_main === UserRole::USER_ROLE_ADMIN; && $user->user_role_main === UserRole::USER_ROLE_ADMIN;
+2 -2
View File
@@ -61,7 +61,7 @@ class CronTaskHandleProvider extends CommonController
private function runTask(CronTask $task) private function runTask(CronTask $task)
{ {
$logger = $this->taskLogger($task->name, app('tenant')); $logger = $this->taskLogger($task->name, currentTenant());
app()->instance('taskLogger', $logger); app()->instance('taskLogger', $logger);
$taskClass = "\\App\\Tasks\\" . $task->name; $taskClass = "\\App\\Tasks\\" . $task->name;
@@ -73,7 +73,7 @@ class CronTaskHandleProvider extends CommonController
$lastRun = []; $lastRun = [];
} }
$lastRun[app('tenant')->slug] = now(); $lastRun[currentTenant()->slug] = now();
// Update last_run // Update last_run
$task->last_run = $lastRun; $task->last_run = $lastRun;
$task->save(); $task->save();
+4 -4
View File
@@ -22,7 +22,7 @@ class GlobalDataProvider {
private ?User $user; private ?User $user;
public function __invoke() { public function __invoke() {
$this->user = auth()->user(); $this->user = currentUser();
$canAccessAdmin = false; $canAccessAdmin = false;
$isMainAdmin = false; $isMainAdmin = false;
@@ -38,7 +38,7 @@ class GlobalDataProvider {
return response()->json([ return response()->json([
'user' => null !== $this->user ? new UserResource($this->user)->toArray(request()) : null, 'user' => null !== $this->user ? new UserResource($this->user)->toArray(request()) : null,
'navbar' => $this->generateNavbar(), 'navbar' => $this->generateNavbar(),
'tenant' => app('tenant'), 'tenant' => currentTenant(),
'activeUsers' => $this->getActiveUsers(), 'activeUsers' => $this->getActiveUsers(),
'version' => config('app.version'), 'version' => config('app.version'),
'currentEvent' => $this->getCurrentEventData(), 'currentEvent' => $this->getCurrentEventData(),
@@ -189,8 +189,8 @@ class GlobalDataProvider {
$activeUsers = []; $activeUsers = [];
$conditions = ['active' => true]; $conditions = ['active' => true];
if (app('tenant')->slug !== 'lv') { if (currentTenant()->slug !== 'lv') {
$conditions['local_group'] = app('tenant')->slug; $conditions['local_group'] = currentTenant()->slug;
} }
foreach ($rawUsers = User::where($conditions)->get() as $user) { foreach ($rawUsers = User::where($conditions)->get() as $user) {
+1 -1
View File
@@ -16,7 +16,7 @@ final class InertiaProvider
private ?User $user; private ?User $user;
public function __construct(string $vueFile, array $props) { public function __construct(string $vueFile, array $props) {
$this->user = auth()->user(); $this->user = currentUser();
$this->vueFile = $vueFile; $this->vueFile = $vueFile;
$this->props = $props; $this->props = $props;
} }
+2 -2
View File
@@ -20,7 +20,7 @@ class TenantUserProvider extends EloquentUserProvider
} }
// Auf "lv" gilt grundsätzlich keine local_group-Einschränkung. // Auf "lv" gilt grundsätzlich keine local_group-Einschränkung.
if (app('tenant')->slug === 'lv') { if (currentTenant()->slug === 'lv') {
return $query->first(); return $query->first();
} }
@@ -30,7 +30,7 @@ class TenantUserProvider extends EloquentUserProvider
// -> "Bundesrecht steht über Landesrecht": Login überall möglich. // -> "Bundesrecht steht über Landesrecht": Login überall möglich.
$query->where('active', true) $query->where('active', true)
->where(function ($q) { ->where(function ($q) {
$q->where('local_group', app('tenant')->slug) $q->where('local_group', currentTenant()->slug)
->orWhere('user_role_main', UserRole::USER_ROLE_ADMIN); ->orWhere('user_role_main', UserRole::USER_ROLE_ADMIN);
}); });
+1 -1
View File
@@ -25,7 +25,7 @@ class UploadFileProvider {
* wo alle anderen Belege liegen. * wo alle anderen Belege liegen.
*/ */
public static function directoryFor(CostUnit $costUnit) : string { public static function directoryFor(CostUnit $costUnit) : string {
return sprintf('%1$s/invoices/%2$s', app('tenant')->slug, $costUnit->id); return sprintf('%1$s/invoices/%2$s', currentTenant()->slug, $costUnit->id);
} }
public function saveUploadedFile() : ?InvoiceFile { public function saveUploadedFile() : ?InvoiceFile {
+3 -3
View File
@@ -2,6 +2,7 @@
namespace App\Repositories; namespace App\Repositories;
use \currentUser;
use App\Enumerations\CostUnitType; use App\Enumerations\CostUnitType;
use App\Enumerations\InvoiceStatus; use App\Enumerations\InvoiceStatus;
use App\Enumerations\InvoiceType; use App\Enumerations\InvoiceType;
@@ -67,8 +68,7 @@ class CostUnitRepository {
} }
public function getCostUnitsByCriteria(array $criteria, bool $forDisplay = true, $disableAccessCheck = false) : array { public function getCostUnitsByCriteria(array $criteria, bool $forDisplay = true, $disableAccessCheck = false) : array {
$user = Auth()->user(); $user = currentUser();
if ($disableAccessCheck) { if ($disableAccessCheck) {
$canSeeAll = true; $canSeeAll = true;
} else { } else {
@@ -97,7 +97,7 @@ class CostUnitRepository {
public function listForSummary(int $maxCountCostUnits) : array { public function listForSummary(int $maxCountCostUnits) : array {
$costUnits = $this->getCostUnitsByCriteria([ $costUnits = $this->getCostUnitsByCriteria([
'archived' => false, 'archived' => false,
'tenant' => app('tenant')->slug, 'tenant' => currentTenant()->slug,
],false); ],false);
foreach ($costUnits as &$cu) { foreach ($costUnits as &$cu) {
@@ -297,7 +297,7 @@ class EventParticipantRepository {
public function getMyParticipations(?int $maxEvents = null) : array { public function getMyParticipations(?int $maxEvents = null) : array {
$participations = []; $participations = [];
$user = auth()->user(); $user = currentUser();
if ($user === null) { if ($user === null) {
return $participations; return $participations;
} }
@@ -326,13 +326,13 @@ class EventParticipantRepository {
} }
public function getMyParticipationByIdentifier(string $identifier) : ?EventParticipant { public function getMyParticipationByIdentifier(string $identifier) : ?EventParticipant {
$user = auth()->user(); $user = currentUser();
if ($user === null) { if ($user === null) {
return null; return null;
} }
return EventParticipant::where('identifier', $identifier) return EventParticipant::where('identifier', $identifier)
->where('tenant', app('tenant')->slug) ->where('tenant', currentTenant()->slug)
->where('user_id', $user->id) ->where('user_id', $user->id)
->whereNull('unregistered_at') ->whereNull('unregistered_at')
->first(); ->first();
+5 -5
View File
@@ -20,7 +20,7 @@ class InvoiceRepository {
]; ];
$user = auth()->user(); $user = currentUser();
if (null === $user) { if (null === $user) {
return $invoices; return $invoices;
} }
@@ -41,7 +41,7 @@ class InvoiceRepository {
} }
public function getUnexportedInvoices() : Collection { public function getUnexportedInvoices() : Collection {
return Invoice::where(['tenant' => app('tenant')->slug, 'status' => InvoiceStatus::INVOICE_STATUS_EXPORTED, 'upload_required' => true])->get(); return Invoice::where(['tenant' => currentTenant()->slug, 'status' => InvoiceStatus::INVOICE_STATUS_EXPORTED, 'upload_required' => true])->get();
} }
public function getByStatus(CostUnit $costUnit, string $status, bool $forDisplay = true) : array { public function getByStatus(CostUnit $costUnit, string $status, bool $forDisplay = true) : array {
@@ -63,8 +63,8 @@ class InvoiceRepository {
foreach (Invoice::where( foreach (Invoice::where(
[ [
'status' => $status, 'status' => $status,
'user_id' => auth()->user()->id, 'user_id' => currentUserOrFail()->id,
'tenant' => app('tenant')->slug, 'tenant' => currentTenant()->slug,
] ]
)->get() as $invoice) { )->get() as $invoice) {
@@ -79,7 +79,7 @@ class InvoiceRepository {
return null; return null;
} }
$isTreasurer = $invoice->costUnit()->first()->treasurers()->where('user_id', auth()->user()->id)->exists(); $isTreasurer = $invoice->costUnit()->first()->treasurers()->where('user_id', currentUserOrFail()->id)->exists();
if ($isTreasurer) { if ($isTreasurer) {
return $invoice; return $invoice;
} }
+2 -2
View File
@@ -20,7 +20,7 @@ class UserRepository {
} }
public function getCurrentUserDetails() : array { public function getCurrentUserDetails() : array {
$user = auth()->user(); $user = currentUser();
$return = [ $return = [
'userId' => null, 'userId' => null,
@@ -31,7 +31,7 @@ class UserRepository {
'userAccountIban' => '', 'userAccountIban' => '',
]; ];
if (null !== auth()->user()) { if ($user !== null) {
$return = [ $return = [
'userId' => $user->id, 'userId' => $user->id,
'userName' => trim($user->getOfficialName()), 'userName' => trim($user->getOfficialName()),
+2 -2
View File
@@ -27,8 +27,8 @@ class EventResource extends JsonResource{
'id' => $this->event->id, 'id' => $this->event->id,
'name' => $this->event->name, 'name' => $this->event->name,
'identifier' => $this->event->identifier, 'identifier' => $this->event->identifier,
'url' => 'https://' . app('tenant')->url . '/event/' . $this->event->identifier . '/signup', 'url' => 'https://' . currentTenant()->url . '/event/' . $this->event->identifier . '/signup',
'urlShort' => 'https://' . app('tenant')->url . '/event/' . $this->event->identifier, 'urlShort' => 'https://' . currentTenant()->url . '/event/' . $this->event->identifier,
'location' => $this->event->location, 'location' => $this->event->location,
'postalCode' => $this->event->postal_code, 'postalCode' => $this->event->postal_code,
'email' => $this->event->email, 'email' => $this->event->email,
+1 -1
View File
@@ -31,7 +31,7 @@ abstract class CommonController {
protected AdminTenantRepository $adminTenants; protected AdminTenantRepository $adminTenants;
public function __construct() { public function __construct() {
$this->tenant = app('tenant'); $this->tenant = currentTenant();
$this->users = new UserRepository(); $this->users = new UserRepository();
$this->costUnits = new CostUnitRepository(); $this->costUnits = new CostUnitRepository();
$this->pageTexts = new PageTextRepository(); $this->pageTexts = new PageTextRepository();
+1 -1
View File
@@ -9,6 +9,6 @@ class SiteScope implements Scope
{ {
public function apply(Builder $builder, Model $model): void public function apply(Builder $builder, Model $model): void
{ {
$builder->where($model->getTable() . '.tenant', app('tenant')->slug); $builder->where($model->getTable() . '.tenant', currentTenant()->slug);
} }
} }
+36
View File
@@ -0,0 +1,36 @@
<?php
use App\Models\Tenant;
use App\Models\User;
use Illuminate\Auth\AuthenticationException;
use Illuminate\Support\Facades\Auth;
if (!function_exists('currentUser')) {
/**
* Der aktuell eingeloggte Nutzer, oder null wenn niemand eingeloggt ist.
*/
function currentUser() : ?User {
return Auth::user();
}
}
if (!function_exists('currentUserOrFail')) {
/**
* Der aktuell eingeloggte Nutzer. Für Code hinter der auth-Middleware,
* wo ein fehlender Nutzer ein Programmierfehler ist.
*
* @throws AuthenticationException
*/
function currentUserOrFail() : User {
return Auth::user() ?? throw new AuthenticationException();
}
}
if (!function_exists('currentTenant')) {
/**
* Der über IdentifyTenant aufgelöste Tenant der aktuellen Anfrage.
*/
function currentTenant() : Tenant {
return app('tenant');
}
}
+1 -1
View File
@@ -10,7 +10,7 @@ use Psr\Log\LoggerInterface;
class UploadInvoices implements CronTask { class UploadInvoices implements CronTask {
public function handle(): void public function handle(): void
{ {
if (!app('tenant')->upload_exports) { if (!currentTenant()->upload_exports) {
return; return;
} }
+4
View File
@@ -20,6 +20,7 @@
"maennchen/zipstream-php": "^3.1" "maennchen/zipstream-php": "^3.1"
}, },
"require-dev": { "require-dev": {
"barryvdh/laravel-ide-helper": "^3.7",
"fakerphp/faker": "^1.23", "fakerphp/faker": "^1.23",
"laravel/pail": "^1.2.2", "laravel/pail": "^1.2.2",
"laravel/pint": "^1.24", "laravel/pint": "^1.24",
@@ -29,6 +30,9 @@
"phpunit/phpunit": "^11.5.3" "phpunit/phpunit": "^11.5.3"
}, },
"autoload": { "autoload": {
"files": [
"app/Support/helpers.php"
],
"psr-4": { "psr-4": {
"App\\": "app/", "App\\": "app/",
"Database\\Factories\\": "database/factories/", "Database\\Factories\\": "database/factories/",
Generated
+293 -1
View File
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "9fb8095137a8e9d664e44b9fca5f1f5a", "content-hash": "6e38fe16a000f12f5fff089b08b49780",
"packages": [ "packages": [
{ {
"name": "bacon/bacon-qr-code", "name": "bacon/bacon-qr-code",
@@ -6934,6 +6934,298 @@
} }
], ],
"packages-dev": [ "packages-dev": [
{
"name": "barryvdh/laravel-ide-helper",
"version": "v3.7.0",
"source": {
"type": "git",
"url": "https://github.com/barryvdh/laravel-ide-helper.git",
"reference": "ad7e37676f1ff985d55ef1b6b96a0c0a40f2609a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/barryvdh/laravel-ide-helper/zipball/ad7e37676f1ff985d55ef1b6b96a0c0a40f2609a",
"reference": "ad7e37676f1ff985d55ef1b6b96a0c0a40f2609a",
"shasum": ""
},
"require": {
"barryvdh/reflection-docblock": "^2.4",
"composer/class-map-generator": "^1.0",
"ext-json": "*",
"illuminate/console": "^11.15 || ^12 || ^13.0",
"illuminate/database": "^11.15 || ^12 || ^13.0",
"illuminate/filesystem": "^11.15 || ^12 || ^13.0",
"illuminate/support": "^11.15 || ^12 || ^13.0",
"php": "^8.2"
},
"require-dev": {
"ext-pdo_sqlite": "*",
"friendsofphp/php-cs-fixer": "^3",
"illuminate/config": "^11.15 || ^12 || ^13.0",
"illuminate/view": "^11.15 || ^12 || ^13.0",
"larastan/larastan": "^3.1",
"mockery/mockery": "^1.4",
"orchestra/testbench": "^9.2 || ^10 || ^11.0",
"phpstan/phpstan-phpunit": "^2.0",
"phpunit/phpunit": "^10.5 || ^11.5.3 || ^12.5.12",
"spatie/phpunit-snapshot-assertions": "^4 || ^5",
"vlucas/phpdotenv": "^5"
},
"suggest": {
"illuminate/events": "Required for automatic helper generation (^6|^7|^8|^9|^10|^11)."
},
"type": "library",
"extra": {
"laravel": {
"providers": [
"Barryvdh\\LaravelIdeHelper\\IdeHelperServiceProvider"
]
},
"branch-alias": {
"dev-master": "3.6-dev"
}
},
"autoload": {
"psr-4": {
"Barryvdh\\LaravelIdeHelper\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Barry vd. Heuvel",
"email": "barryvdh@gmail.com"
}
],
"description": "Laravel IDE Helper, generates correct PHPDocs for all Facade classes, to improve auto-completion.",
"keywords": [
"autocomplete",
"codeintel",
"dev",
"helper",
"ide",
"laravel",
"netbeans",
"phpdoc",
"phpstorm",
"sublime"
],
"support": {
"issues": "https://github.com/barryvdh/laravel-ide-helper/issues",
"source": "https://github.com/barryvdh/laravel-ide-helper/tree/v3.7.0"
},
"funding": [
{
"url": "https://fruitcake.nl",
"type": "custom"
},
{
"url": "https://github.com/barryvdh",
"type": "github"
}
],
"time": "2026-03-17T14:12:51+00:00"
},
{
"name": "barryvdh/reflection-docblock",
"version": "v2.4.1",
"source": {
"type": "git",
"url": "https://github.com/barryvdh/ReflectionDocBlock.git",
"reference": "4f5ba70c30c81f2ce03a16a9965832cfcc31ed3b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/barryvdh/ReflectionDocBlock/zipball/4f5ba70c30c81f2ce03a16a9965832cfcc31ed3b",
"reference": "4f5ba70c30c81f2ce03a16a9965832cfcc31ed3b",
"shasum": ""
},
"require": {
"php": ">=7.1"
},
"require-dev": {
"phpunit/phpunit": "^8.5.14|^9"
},
"suggest": {
"dflydev/markdown": "~1.0",
"erusev/parsedown": "~1.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.3.x-dev"
}
},
"autoload": {
"psr-0": {
"Barryvdh": [
"src/"
]
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Mike van Riel",
"email": "mike.vanriel@naenius.com"
}
],
"support": {
"source": "https://github.com/barryvdh/ReflectionDocBlock/tree/v2.4.1"
},
"time": "2026-03-05T20:09:01+00:00"
},
{
"name": "composer/class-map-generator",
"version": "1.7.3",
"source": {
"type": "git",
"url": "https://github.com/composer/class-map-generator.git",
"reference": "86d8208fc3c649a3a999daf1a63c25201be2990f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/composer/class-map-generator/zipball/86d8208fc3c649a3a999daf1a63c25201be2990f",
"reference": "86d8208fc3c649a3a999daf1a63c25201be2990f",
"shasum": ""
},
"require": {
"composer/pcre": "^2.1 || ^3.1",
"php": "^7.2 || ^8.0",
"symfony/finder": "^4.4 || ^5.3 || ^6 || ^7 || ^8"
},
"require-dev": {
"phpstan/phpstan": "^1.12 || ^2",
"phpstan/phpstan-deprecation-rules": "^1 || ^2",
"phpstan/phpstan-phpunit": "^1 || ^2",
"phpstan/phpstan-strict-rules": "^1.1 || ^2",
"phpunit/phpunit": "^8",
"symfony/filesystem": "^5.4 || ^6 || ^7 || ^8"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "1.x-dev"
}
},
"autoload": {
"psr-4": {
"Composer\\ClassMapGenerator\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Jordi Boggiano",
"email": "j.boggiano@seld.be",
"homepage": "https://seld.be"
}
],
"description": "Utilities to scan PHP code and generate class maps.",
"keywords": [
"classmap"
],
"support": {
"issues": "https://github.com/composer/class-map-generator/issues",
"source": "https://github.com/composer/class-map-generator/tree/1.7.3"
},
"funding": [
{
"url": "https://packagist.com",
"type": "custom"
},
{
"url": "https://github.com/composer",
"type": "github"
}
],
"time": "2026-05-05T09:17:07+00:00"
},
{
"name": "composer/pcre",
"version": "3.4.0",
"source": {
"type": "git",
"url": "https://github.com/composer/pcre.git",
"reference": "d5a341b3fb61f3001970940afb1d332968a183ed"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/composer/pcre/zipball/d5a341b3fb61f3001970940afb1d332968a183ed",
"reference": "d5a341b3fb61f3001970940afb1d332968a183ed",
"shasum": ""
},
"require": {
"php": "^7.4 || ^8.0"
},
"conflict": {
"phpstan/phpstan": "<2.2.2"
},
"require-dev": {
"phpstan/phpstan": "^2",
"phpstan/phpstan-deprecation-rules": "^2",
"phpstan/phpstan-strict-rules": "^2",
"phpunit/phpunit": "^9"
},
"type": "library",
"extra": {
"phpstan": {
"includes": [
"extension.neon"
]
},
"branch-alias": {
"dev-main": "3.x-dev"
}
},
"autoload": {
"psr-4": {
"Composer\\Pcre\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Jordi Boggiano",
"email": "j.boggiano@seld.be",
"homepage": "http://seld.be"
}
],
"description": "PCRE wrapping library that offers type-safe preg_* replacements.",
"keywords": [
"PCRE",
"preg",
"regex",
"regular expression"
],
"support": {
"issues": "https://github.com/composer/pcre/issues",
"source": "https://github.com/composer/pcre/tree/3.4.0"
},
"funding": [
{
"url": "https://packagist.com",
"type": "custom"
},
{
"url": "https://github.com/composer",
"type": "github"
}
],
"time": "2026-06-07T11:47:49+00:00"
},
{ {
"name": "fakerphp/faker", "name": "fakerphp/faker",
"version": "v1.24.1", "version": "v1.24.1",