has('path') && ! $this->has('hits')) { $this->merge(['hits' => [$this->only(['path', 'locale', 'referrer'])]]); } } /** * @return array */ public function rules(): array { return [ 'hits' => ['required', 'array', 'min:1', 'max:'.$this->maxBatch()], // Paths, not URLs: the frontend knows its own origin, and a report // carrying a full address would let a caller file a 404 against // somebody else's domain. 'hits.*.path' => ['required', 'string', 'max:500', 'starts_with:/'], 'hits.*.locale' => [ 'sometimes', 'nullable', 'string', Rule::in(array_keys((array) config('locales.supported'))), ], // Where the visitor came from, verbatim from the Referer header, // so it can be a URL on anybody's domain. 'hits.*.referrer' => ['sometimes', 'nullable', 'string', 'url:http,https', 'max:500'], ]; } /** * @return array> */ public function hits(): array { return array_values((array) $this->validated('hits')); } public function maxBatch(): int { return max(1, (int) config('site.telemetry.max_batch', 50)); } }