'array' ]; public function groups(): BelongsToMany { return $this->belongsToMany(FieldsGroup::class, 'fields_group_fields', 'field_id', 'group_id'); } public function values(): HasMany { return $this->hasMany(FieldType::CLASSES[$this->type]); } public function objectValues($objectId): HasMany { return $this->values()->where(['object_id' => $objectId])->orderBy('ord'); } public function objectsValues(array $ids): HasMany { return $this->values()->whereIn('object_id', $ids); } public function objectTypeValues($objectTypeId): HasMany { return $this->values()->whereHas('object', function($query) use($objectTypeId) { $query->where(['type_id' => $objectTypeId]); }); } public function getOptionsAttribute(): ?Collection { if (($this->type === FieldType::RELATION) && !empty($this->params['options']['show'])) { if ($model = $this->params['related'] ?? null) { $query = $model::query(); collect($this->params['options']['whereHas'] ?? [])->each(function($val, $prop) use($query) { $query->whereHas($prop, function($query) use($val) { foreach ($val as $attr => $v) { $query->where([$attr => $v]); } }); }); if ($where = $this->params['options']['where'] ?? null) $query->where($where); return $query->get(); } } return null; } public function getTransformerAttribute() { $transformer = $this->params['transformer'] ?? OptionTransformer::class; return new $transformer; } public function getIsFileAttribute(): bool { return in_array($this->type, [FieldType::DOCUMENT, FieldType::IMAGE]); } public function getRepresented($filters = [], ?FiltersService $service = null): ?Collection { if ($model = $this->params['related'] ?? null) { $query = $model::whereHas('relationValues', function($query) use($filters, $service) { $query->where(['field_id' => $this->id])->whereHas('object', function($query) use($filters, $service) { self::applyFilters($query, collect($filters)->except($this->name), $service); }); }); return $query->get(); } return null; } public function getRange($filters = [], ?FiltersService $service = null): ?array { if (in_array($this->type, [FieldType::INTEGER, FieldType::FLOAT, FieldType::DATE, FieldType::DATETIME])) { $query = $this->values()->whereHas('object', function($query) use($filters, $service) { self::applyFilters($query, collect($filters)->except($this->name), $service); }); return ['min' => $query->min('value') ?? 0, 'max' => $query->max('value') ?? 0]; } return null; } public function getValue($objectId) { return $this->objectValues($objectId)->get()->map(function($value) { return $value->get(); }); } public function setValue($objectId, $value) { if ($this->multiple) $this->objectValues($objectId)->delete(); if (!($value instanceof Collection)) $value = collect((is_array($value) && !Arr::isAssoc($value)) ? $value : [$value]); $value->each(function($value, $ord) use($objectId) { if ($this->multiple) $this->values()->create(['object_id' => $objectId, 'ord' => $ord])->set($value); else $this->values()->firstOrCreate(['object_id' => $objectId])->set($value); }); return $this->getValue($objectId); } public function addValue($objectId, $value) { if ($this->multiple) { $max = $this->objectValues($objectId)->max('ord'); if (is_null($max)) $max = -1; if (!($value instanceof Collection)) $value = collect((is_array($value) && !Arr::isAssoc($value)) ? $value : [$value]); $value->each(function($value, $ord) use($objectId, $max) { $this->values()->create(['object_id' => $objectId, 'ord' => $max + $ord + 1])->set($value); }); } return $this->getValue($objectId); } public static function applyFilters(Builder $query, Collection $filters, ?FiltersService $service = null) { if ($types = $filters->get('types')) { $types = is_array($types) ? $types : [$types]; $filters->forget('types'); $query->whereHas('type', function($query) use($types) { $query->whereIn('uuid', $types)->orWhereIn('name', $types); }); $filters->filter(function($value) {return $value;})->each(function($value, $prop) use($query, $types, $service) { $field = Field::query()->where(['name' => $prop])->whereHas('groups.objectType', function($query) use($types) { $query->whereIn('uuid', $types)->orWhereIn('name', $types); })->first(); if ($field) $field->applyFilter($query, $value); }); if ($service && $service->objectRelationName) $query->whereHas($service->objectRelationName, function($query) use($service, $filters) { if (method_exists($service, 'applyNativeFilters')) $service->applyNativeFilters($query, $filters); if (method_exists($service, 'applyPermissionsFilters')) $service->applyPermissionsFilters($query); }); } } public function applyFilter($query, $value) { if ($value = $this->prepareFilterValue($value)) $query->whereHas("{$this->type}Values", function($query) use($value) { $query->where(['field_id' => $this->id]); $class = FieldType::CLASSES[$this->type]; $class::applyFilter($query, $value); }); } public function prepareFilterValue($value) { return is_array($value) ? collect($value)->filter(function($val) { return !is_null($val); })->all() : $value; } public function applyOrder(Builder $query, $dir) { if ($table = FieldType::TABLES[$this->type] ?? null) { $query->leftJoin("{$table} as prop-{$this->name}", function(JoinClause $join) use($table) { $join->on('objects.id', '=', "prop-{$this->name}.object_id"); })->where(["prop-{$this->name}.field_id" => $this->id])->orderBy("prop-{$this->name}.value", $dir); } } public function fakeValue($objectId) { $faker = new Generator(); if ($this->type === FieldType::STRING) $value = $faker->sentence(4); elseif ($this->type === FieldType::TEXT) $value = $faker->realText(rand(50, 240)); elseif ($this->type === FieldType::INTEGER) $value = rand(0, 500); elseif ($this->type === FieldType::FLOAT) $value = $faker->randomFloat(1, 0, 100); elseif ($this->type === FieldType::BOOLEAN) $value = boolval(rand(0,1)); elseif ($this->type === FieldType::DATE) $value = $faker->dateTimeBetween('-5 years', '+ 3 years'); elseif ($this->type === FieldType::DATETIME) $value = $faker->dateTimeBetween('-5 years', '+ 3 years'); elseif ($this->type === FieldType::RELATION) $value = $this->options->random(($this->multiple) ? rand(1, 3) : 1); $this->setValue($objectId, $value ?? null); } }