|null field id => value */ private ?array $customFieldValues = null; private ?ClientStorageUsage $storage = null; /** @var array{files: int, folders: int}|null */ private ?array $content = null; /** * The richer single-client shape. * * A named constructor rather than extra __construct parameters: * JsonResource::collection() maps the collection through * `new static($item, $key)`, so widening the constructor silently * breaks every listing with a TypeError on the second argument. * * @param array $customFieldValues field id => value * @param array{files: int, folders: int} $content */ public static function detailed( User $client, array $customFieldValues, ClientStorageUsage $storage, array $content, ): self { $resource = new self($client); $resource->customFieldValues = $customFieldValues; $resource->storage = $storage; $resource->content = $content; return $resource; } /** * @return array */ public function toArray(Request $request): array { $data = [ 'id' => $this->id, 'name' => $this->name, 'email' => $this->email, 'active' => $this->active, 'account_requested' => $this->account_requested, // Whether, not what: the state of the second factor is what a // caller needs to see before removing it. The secret and the // recovery codes stay where they are. 'two_factor_enabled' => $this->hasTwoFactorEnabled(), 'created_at' => $this->created_at?->toIso8601String(), 'updated_at' => $this->updated_at?->toIso8601String(), ]; if ($this->storage !== null) { $quotaMb = $this->storage->quotaMb($this->resource); $data['storage'] = [ // The client's own column, where 0 means "inherit the site // default" rather than "unlimited" — both are reported so a // caller need not know that rule to display it correctly. 'quota_mb' => $this->storage_quota_mb, 'effective_quota_mb' => $quotaMb, 'unlimited' => $quotaMb === 0, 'used_mb' => (int) ceil($this->storage->usedBytes($this->resource) / 1024 / 1024), ]; } if ($this->customFieldValues !== null) { $data['custom_fields'] = ClientCustomField::query() ->orderBy('sort_order') ->orderBy('id') ->get() ->map(fn (ClientCustomField $field): array => [ 'id' => $field->id, 'name' => $field->name, 'label' => $field->label, 'type' => $field->type->value, 'value' => $this->customFieldValues[$field->id] ?? null, ]) ->all(); } if ($this->content !== null) { // What a caller needs in order to answer DELETE's mandatory // content-disposition question before asking. $data['content'] = $this->content; } return $data; } }