Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/raczkodavid/Zooniverse/llms.txt

Use this file to discover all available pages before exploring further.

Zooniverse enforces validation at two layers: standard Laravel form validation applied in the controller before any database writes, and business logic checks that evaluate domain-specific constraints such as enclosure compatibility and capacity. This page documents every rule at both layers for enclosures and animals.

Enclosure Validation

Creating an Enclosure

The following rules are applied in EnclosureController::store():
$request->validate([
    'name'         => 'required',
    'limit'        => 'required|integer|min:1',
    'feeding_time' => 'required|date_format:H:i:s',
]);
FieldRulesNotes
namerequiredAny non-empty string is accepted
limitrequired, integer, min:1Must be at least 1
feeding_timerequired, date_format:H:i:sMust be a full time string including seconds, e.g. 08:30:00

Updating an Enclosure

The rules in EnclosureController::update() are mostly the same, with one important difference for limit:
$request->validate([
    'name'         => 'required|string',
    'limit'        => 'required|integer|min:' . max(1, $enclosure->animals->count()),
    'feeding_time' => 'required',
]);
FieldRulesNotes
namerequired, string
limitrequired, integer, min: max(1, current animal count)Cannot be set below the number of animals currently in the enclosure
feeding_timerequiredFormat is not re-validated on update
The dynamic min on limit prevents an admin from reducing the capacity below the enclosure’s current occupancy. For example, if an enclosure holds 4 animals, the limit cannot be set lower than 4.

Animal Validation

Creating and Updating an Animal

The same validation rules are applied in both AnimalController::store() and AnimalController::update():
$validated = $request->validate([
    'name'         => 'required|string',
    'species'      => 'required|string',
    'type'         => 'required|in:predator,herbivore',
    'born_at'      => 'required|date|before:now|after:01-01-1900',
    'enclosure_id' => 'required|exists:enclosures,id',
]);
FieldRulesNotes
namerequired, string
speciesrequired, stringFree-form species name
typerequired, in:predator,herbivoreControls the is_predator boolean stored in the database
born_atrequired, date, before:now, after:01-01-1900Must be a past date within a plausible range
enclosure_idrequired, exists:enclosures,idThe referenced enclosure must exist in the database
The type field is submitted as a string (predator or herbivore) and mapped to the boolean is_predator column on save: 'is_predator' => $validated['type'] === 'predator'.

Business Logic Validations

Beyond form validation, the controllers enforce domain rules that cannot be expressed with standard Laravel validation rules alone.

Enclosure Compatibility

Before adding or updating an animal, the system checks that the animal’s type matches the enclosure’s existing population:
$isPredator = $request->type == 'predator';

if ($enclosure->isPredatorEnclosure() !== null && $isPredator !== $enclosure->isPredatorEnclosure()) {
    return redirect()
        ->back()
        ->withErrors(['enclosure_id' => 'The selected enclosure is not compatible with the animal type.'])
        ->withInput();
}
The isPredatorEnclosure() method returns null when the enclosure is empty, which signals that either type is acceptable:
public function isPredatorEnclosure(): ?bool
{
    if ($this->animals->isEmpty())
        return null; // both types are acceptable

    return $this->animals->first()->is_predator;
}
Once the first animal is added, the enclosure is locked to that type. A predator enclosure cannot accept herbivores, and vice versa. The only way to change the type is to archive all current animals first.

Enclosure Capacity

After the compatibility check, the system verifies the enclosure is not already full:
if ($enclosure->isFull())
    return redirect()
        ->back()
        ->withErrors(['enclosure_id' => 'The selected enclosure is full.'])
        ->withInput();
public function isFull(): bool
{
    return $this->animals->count() >= $this->limit;
}
This check applies when creating an animal, updating an animal to a different enclosure, and restoring an archived animal.

Enclosure Deletion

An enclosure can only be deleted if it contains no animals:
if ($enclosure->animals->count() > 0) {
    return redirect()->back()->withErrors([
        'enclosure_id' => 'The selected enclosure is not empty. Please remove all animals before deleting the enclosure.'
    ]);
}
All animals must be archived before an enclosure can be deleted. The delete action also calls $enclosure->users()->detach() to clean up the enclosure_user pivot table before removing the enclosure record.

Restore Compatibility

When restoring an archived animal, the same compatibility and capacity logic applies. The Animal::isCompatibleWithEnclosure() method is used directly:
public function isCompatibleWithEnclosure(Enclosure $enclosure): bool
{
    return $this->is_predator == $enclosure->isPredatorEnclosure()
        || $enclosure->isPredatorEnclosure() === null;
}
if (!$animal->isCompatibleWithEnclosure($enclosure))
    return redirect()->back()->withErrors(['enclosure_id' => 'The selected enclosure is not compatible with the animal type.']);

if ($enclosure->isFull())
    return redirect()->back()->withErrors(['enclosure_id' => 'The selected enclosure is full.']);
The archived animals page pre-filters the enclosure dropdown using Animal::getValidEnclosures(), so only compatible, non-full enclosures are presented as options. Server-side validation still runs at submission time.
public function getValidEnclosures()
{
    return Enclosure::all()->filter(function ($enclosure) {
        return ($this->is_predator == $enclosure->isPredatorEnclosure()
                || $enclosure->isPredatorEnclosure() === null)
            && !$enclosure->isFull();
    });
}

Build docs developers (and LLMs) love