Skip to main content

MFR Controllers & Resources

app/Http/Controllers/Mfr/

Pro MFR-Entity gibt es einen Resource-Controller mit den Standard-Methoden index, show, store, update, destroy. Alle haben dasselbe Grundmuster — _ResourceController.php ist die Schablone.

Vorhandene Controller

ControllerEndpoint-PrefixModellResource
CompanyController/v1/mfr/companiesCommon\Mfr\CompaniesCompanyResource
ContactController/v1/mfr/contactsCommon\Mfr\ContactsContactResource
CostCenterController/v1/mfr/costCentersCommon\Mfr\CostCentersCostCenterResource
DocumentController/v1/mfr/documentsCommon\Mfr\DocumentsDocumentResource
ItemController/v1/mfr/itemsCommon\Mfr\ItemsItemResource
ItemTypeController/v1/mfr/itemTypesCommon\Mfr\ItemTypesItemTypeResource
ItemUnitController/v1/mfr/itemUnitsCommon\Mfr\ItemUnitsItemUnitResource
ProductController/v1/mfr/productsCommon\Mfr\ProductsProductResource
QualificationController/v1/mfr/qualificationsCommon\Mfr\QualificationsQualificationResource
ServiceObjectController/v1/mfr/serviceObjectsCommon\Mfr\ServiceObjectsServiceObjectResource
ServiceRequestController/v1/mfr/serviceRequestsCommon\Mfr\ServiceRequestsServiceRequestResource
StepListTemplateController/v1/mfr/stepListTemplates...StepListTemplateResource
TagController/v1/mfr/tags...TagResource
TimeEventController/v1/mfr/timeEvents...TimeEventResource
UserController/v1/mfr/users...UserResource

CRUD-Pattern (am Beispiel CompanyController)

index()

public function index() {
return response()->json([
'data' => CompanyResource::collection(Companies::paginate())
], 200);
}

store() — schreibt zuerst zu MFR, dann lokal

public function store(Request $request, bool $toMfr = true)
{
$request->validate([
'Id' => 'required|string|max:255',
'Version' => 'required|integer',
]);

if ($toMfr) {
$body = json_encode($request->all(), true);
$mfrResponse = $this->guzzle->post($this->entity, $body); // → MFR
}

$company = Companies::create([ // → Common-DB
'Id' => $mfrResponse['body']->Id ?? $request->Id,
'Version' => (int) $request->Version,
]);

return response()->json([
'data' => new CompanyResource($company),
'mfrResponse' => $mfrResponse ?? null,
], 201);
}

update() — mergt + erhöht Version

public function update(Request $request, Companies $company, bool $toMfr = true)
{
if ($toMfr) {
$helper = new Helper();
$merged = $helper->array_merge_deep_override($company->toArray(), $request->toArray());
++$merged['Version'];
$company->update($merged);

$body = $company->makeHidden(['created_at','updated_at','DateModified','DateOfCreation'])->toJson();
$mfrResponse = $this->guzzle->put($this->entity . '(' . $company->Id . 'L)', $body);
} else {
$company->update($request->all());
}

return response()->json([
'data' => new CompanyResource($company),
'mfrResponse' => $mfrResponse ?? null,
], 200);
}

Wichtig: bei $toMfr = true wird Version immer um 1 erhöht — MFR braucht das für sein Optimistic-Locking.

destroy()

public function destroy(Companies $company, bool $toMfr = true)
{
$commonResponse = $company->delete();

if ($toMfr) {
$mfrResponse = $this->guzzle->delete($this->entity . '(' . $company->Id . 'L)');
}

return response()->json([
'data' => $commonResponse,
'mfrResponse' => $mfrResponse ?? null,
], 204);
}

Scramble-Annotations

Die Resource-Controller benutzen Dedoc\Scramble\Attributes\PathParameter für die OpenAPI-Generierung:

#[PathParameter('company', description: 'Show Company for Mfr', type: 'string', format: 'id', example: '61149446314')]
public function show(Companies $company) { ... }

So sieht das /scramble/openapi.json mit korrekten Parametern aus, ohne dass im Body-Comment etwas stehen muss.

Resources

app/Http/Resources/Mfr/<Entity>Resource.php

Klassen erweitern JsonResource und definieren das Wire-Format (PascalCase) — sie sind die Translation-Layer zwischen Eloquent-Modellen und API-Response.

#[SchemaName(name: 'Companies')]
class CompanyResource extends JsonResource
{
public function toArray(Request $request): array
{
return [
'Id' => (string) $this->Id,
'Version' => (int) $this->Version,
'Name' => (string) $this->Name,
'IsPhysicalPerson' => (bool) $this->IsPhysicalPerson,
'Contacts' => (array) $this->Contacts,
'Tags' => (array) $this->Tags,
'ServiceObjects' => (array) $this->ServiceObjects,
// ... 20 weitere Felder
];
}
}

#[SchemaName('Companies')] sorgt dafür, dass Scramble in der OpenAPI-Schema-Liste den Namen Companies verwendet (und nicht CompanyResource).

_ResourceController.php als Schablone

app/Http/Controllers/Mfr/_ResourceController.php ist die Vorlage für alle weiteren Entities. Wenn du eine neue Entity anbinden willst:

  1. Datei kopieren als <Entity>Controller.php
  2. protected string $entity = '<EntityNameInMFR>'; setzen
  3. Modell- und Resource-Imports anpassen (Companies → dein Modell)
  4. Route in routes/mfr.php registrieren
  5. Modell unter app/Models/Common/Mfr/ erstellen + Migration schreiben

MfrController (Top-Level Sync-Tools)

App\Http\Controllers\MfrController (NICHT in Mfr/-Subordner) ist der Top-Level-Controller für Sync-/Setup-Operationen:

RouteMethodeZweck
GET /api/v1/mfr/showindexVerfügbare Entities ausgeben
GET /api/v1/mfr/show/{e?}/{a?}/{v?}showEinzelnen Datensatz inspizieren
GET /api/v1/mfr/sync/{entity?}syncOData-Pull → Common-DB
GET /api/v1/mfr/setup/{stage?}setupinitiales Setup je Stage
GET /api/v1/mfr/post/{stage?}/{type?}/{e?}postBulk-Push Common-DB → MFR

Diese Routen sind primär als interne CLI-/Sync-Tools gedacht — sie laufen unter auth:sanctum, sollten aber im Production-Frontend nicht direkt aufgerufen werden.