Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 4 additions & 12 deletions packages/support/src/Concerns/CanBeCopied.php
Original file line number Diff line number Diff line change
Expand Up @@ -44,29 +44,21 @@ public function copyMessageDuration(int | Closure | null $duration): static

public function isCopyable(mixed $state): bool
{
return (bool) $this->evaluate($this->isCopyable, [
'state' => $state,
]);
return (bool) $this->evaluate($this->isCopyable, $this->getEvaluationsForStateItem($state));
}

public function getCopyableState(mixed $state): ?string
{
return $this->evaluate($this->copyableState, [
'state' => $state,
]);
return $this->evaluate($this->copyableState, $this->getEvaluationsForStateItem($state));
}

public function getCopyMessage(mixed $state): string
{
return $this->evaluate($this->copyMessage, [
'state' => $state,
]) ?? __('filament::components/copyable.messages.copied');
return $this->evaluate($this->copyMessage, $this->getEvaluationsForStateItem($state)) ?? __('filament::components/copyable.messages.copied');
}

public function getCopyMessageDuration(mixed $state): int
{
return $this->evaluate($this->copyMessageDuration, [
'state' => $state,
]) ?? 2000;
return $this->evaluate($this->copyMessageDuration, $this->getEvaluationsForStateItem($state)) ?? 2000;
}
}
12 changes: 12 additions & 0 deletions packages/support/src/Concerns/EvaluatesClosures.php
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,18 @@ protected function resolveDefaultClosureDependencyForEvaluationByType(string $pa
return [];
}

/**
* @return array<string, mixed>
*/
protected function getEvaluationsForStateItem(mixed $state): array
{
if (method_exists($this, 'getNamedInjectionsForStateItem')) {
return $this->getNamedInjectionsForStateItem($state);
}

return ['state' => $state];
}

protected function getTypedReflectionParameterClassName(ReflectionParameter $parameter): ?string
{
$type = $parameter->getType();
Expand Down
149 changes: 117 additions & 32 deletions packages/support/src/Concerns/HasCellState.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,16 @@ trait HasCellState
*/
protected array $cachedState = [];

/**
* @var array<string, array<Model>>
*/
protected array $cachedRelationshipRecords = [];

/**
* @var array<Model>|null
*/
protected ?array $lastResolvedRelationshipRecords = null;

protected ?bool $hasMultipleRelationshipCache = null;

protected ?Relation $relationshipCache = null;
Expand Down Expand Up @@ -112,30 +122,13 @@ public function getStateFromRecord(): mixed
$relationship = $this->getRelationship($record);

if ($relationship) {
$relationshipAttribute = $this->getFullAttributeName($record);

$state = collect($this->getRelationshipResults($record))
->reduce(
function (Collection $carry, Model $record) use ($relationshipAttribute): Collection {
if (
($record instanceof HasRichContent) &&
$record->hasRichContentAttribute($relationshipAttribute)
) {
$state = $record->getRichContentAttribute($relationshipAttribute);
} else {
$state = data_get($record, $relationshipAttribute);
}

if (blank($state)) {
return $carry;
}

return $carry->push($state);
},
initial: collect(),
)
->when($this->isDistinctList(), fn (Collection $state) => $state->unique())
->values();
$pairs = $this->resolveRelationshipStatePairs($record);

$this->lastResolvedRelationshipRecords = $pairs
->pluck('record')
->all();

$state = $pairs->pluck('state');

if (! $state->count()) {
return null;
Expand All @@ -149,6 +142,8 @@ function (Collection $carry, Model $record) use ($relationshipAttribute): Collec
}
}

$this->lastResolvedRelationshipRecords = null;

$name = $this->getName();

if (
Expand All @@ -166,6 +161,79 @@ function (Collection $carry, Model $record) use ($relationshipAttribute): Collec
public function clearCachedState(): void
{
$this->cachedState = [];
$this->cachedRelationshipRecords = [];
}

/**
* @return array<Model>
*/
public function getRelationshipRecords(): array
{
$this->getState();

$record = $this->getRecord();

if (! $record) {
return [];
}

$recordKey = $this->resolveCachedStateRecordKey($record);

if (blank($recordKey)) {
return $this->lastResolvedRelationshipRecords ?? [];
}

return $this->cachedRelationshipRecords[$recordKey] ?? [];
}

public function getRelationshipRecord(): ?Model
{
$records = $this->getRelationshipRecords();

if (count($records) !== 1) {
return null;
}

return $records[0];
}

/**
* @return Collection<int, array{state: mixed, record: Model}>
*/
protected function resolveRelationshipStatePairs(Model $record): Collection
{
$relationshipAttribute = $this->getFullAttributeName($record);

return collect($this->getRelationshipResults($record))
->map(function (Model $relatedRecord) use ($relationshipAttribute): ?array {
if (
($relatedRecord instanceof HasRichContent) &&
$relatedRecord->hasRichContentAttribute($relationshipAttribute)
) {
$state = $relatedRecord->getRichContentAttribute($relationshipAttribute);
} else {
$state = data_get($relatedRecord, $relationshipAttribute);
}

if (blank($state)) {
return null;
}

return [
'state' => $state,
'record' => $relatedRecord,
];
})
->filter()
->when(
$this->isDistinctList(),
fn (Collection $pairs) => $pairs->unique(
fn (array $pair): string => is_scalar($pair['state'])
? (string) $pair['state']
: serialize($pair['state']),
),
)
->values();
}

public function separator(string | Closure | null $separator = ','): static
Expand Down Expand Up @@ -467,23 +535,40 @@ protected function cacheState(Closure $state): mixed
return null;
}

if ($this instanceof Column) {
$recordKey = $this->getLivewire()->getTableRecordKey($record);
} elseif (is_array($record)) { /** @phpstan-ignore function.impossibleType */
$recordKey = (string) ($record[ArrayRecord::getKeyName()] ?? null); /** @phpstan-ignore nullCoalesce.offset */
} else {
$recordKey = (string) $record->getKey();
}
$recordKey = $this->resolveCachedStateRecordKey($record);

if (blank($recordKey)) {
$this->lastResolvedRelationshipRecords = null;

return $state();
}

if (array_key_exists($recordKey, $this->cachedState)) {
return $this->cachedState[$recordKey];
}

return $this->cachedState[$recordKey] = $state();
$this->lastResolvedRelationshipRecords = null;

$computedState = $state();

if ($this->lastResolvedRelationshipRecords !== null) {
$this->cachedRelationshipRecords[$recordKey] = $this->lastResolvedRelationshipRecords;
}

return $this->cachedState[$recordKey] = $computedState;
}

protected function resolveCachedStateRecordKey(mixed $record): ?string
{
if ($this instanceof Column) {
return $this->getLivewire()->getTableRecordKey($record);
}

if (is_array($record)) { /** @phpstan-ignore function.impossibleType */
return (string) ($record[ArrayRecord::getKeyName()] ?? null); /** @phpstan-ignore nullCoalesce.offset */
}

return (string) $record->getKey();
}

public function getGetStateUsingCallback(): mixed
Expand Down
4 changes: 1 addition & 3 deletions packages/support/src/Concerns/HasFontFamily.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,7 @@ public function fontFamily(FontFamily | string | Closure | null $family): static

public function getFontFamily(mixed $state = null): FontFamily | string | null
{
$family = $this->evaluate($this->fontFamily, [
'state' => $state,
]);
$family = $this->evaluate($this->fontFamily, $this->getEvaluationsForStateItem($state));

if (is_string($family)) {
$family = FontFamily::tryFrom($family) ?? $family;
Expand Down
4 changes: 1 addition & 3 deletions packages/support/src/Concerns/HasWeight.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,7 @@ public function weight(FontWeight | string | Closure | null $weight): static

public function getWeight(mixed $state = null): FontWeight | string | null
{
$weight = $this->evaluate($this->weight, [
'state' => $state,
]);
$weight = $this->evaluate($this->weight, $this->getEvaluationsForStateItem($state));

if (! is_string($weight)) {
return $weight;
Expand Down
2 changes: 2 additions & 0 deletions packages/tables/src/Columns/Column.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ class Column extends ViewComponent
use Concerns\HasLabel;
use Concerns\HasName;
use Concerns\HasRecord;
use Concerns\HasRelationshipRecords;
use Concerns\HasRowLoopObject;
use Concerns\InteractsWithTableQuery;
use HasAlignment;
Expand Down Expand Up @@ -100,6 +101,7 @@ protected function resolveDefaultClosureDependencyForEvaluationByName(string $pa
return match ($parameterName) {
'livewire' => [$this->getLivewire()],
'record' => [$this->getRecord()],
'relationshipRecord' => [$this->getRelationshipRecord()],
'rowLoop' => [$this->getRowLoop()],
'state' => [$this->getState()],
'table' => [$this->getTable()],
Expand Down
7 changes: 3 additions & 4 deletions packages/tables/src/Columns/Concerns/CanFormatState.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
use Filament\Support\Facades\FilamentTimezone;
use Filament\Tables\Columns\TextColumn;
use Illuminate\Contracts\Support\Htmlable;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Carbon;
use Illuminate\Support\HtmlString;
use Illuminate\Support\Number;
Expand Down Expand Up @@ -373,13 +374,11 @@ public function formatStateUsing(?Closure $callback): static
return $this;
}

public function formatState(mixed $state): mixed
public function formatState(mixed $state, ?Model $relationshipRecord = null): mixed
{
$isHtml = $this->isHtml();

$state = $this->evaluate($this->formatStateUsing ?? $state, [
'state' => $state,
]);
$state = $this->evaluateForStateItem($this->formatStateUsing ?? $state, $state, $relationshipRecord);

if (is_array($state)) {
$state = json_encode($state);
Expand Down
12 changes: 6 additions & 6 deletions packages/tables/src/Columns/Concerns/CanOpenUrl.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace Filament\Tables\Columns\Concerns;

use Closure;
use Illuminate\Database\Eloquent\Model;

trait CanOpenUrl
{
Expand Down Expand Up @@ -32,13 +33,11 @@ public function url(string | Closure | null $url, bool | Closure | null $shouldO
return $this;
}

public function getUrl(mixed $state = null): ?string
public function getUrl(mixed $state = null, ?Model $relationshipRecord = null): ?string
{
if (func_num_args() === 1) {
if (func_num_args() >= 1) {
return $this->hasStateBasedUrls()
? $this->evaluate($this->url, [
'state' => $state,
])
? $this->evaluateForStateItem($this->url, $state, $relationshipRecord)
: null;
}

Expand All @@ -51,7 +50,8 @@ public function getUrl(mixed $state = null): ?string

public function hasStateBasedUrls(): bool
{
return $this->evaluationValueIsFunctionAndHasParameter($this->url, parameterName: 'state');
return $this->evaluationValueIsFunctionAndHasParameter($this->url, parameterName: 'state')
|| $this->evaluationValueIsFunctionAndHasParameter($this->url, parameterName: 'relationshipRecord');
}

public function shouldOpenUrlInNewTab(): bool
Expand Down
7 changes: 3 additions & 4 deletions packages/tables/src/Columns/Concerns/HasColor.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
use Closure;
use Filament\Support\Contracts\HasColor as ColorInterface;
use Filament\Tables\Columns\Column;
use Illuminate\Database\Eloquent\Model;

trait HasColor
{
Expand Down Expand Up @@ -52,11 +53,9 @@ public function colors(array | Closure $colors): static
/**
* @return string | array<string> | null
*/
public function getColor(mixed $state): string | array | null
public function getColor(mixed $state, ?Model $relationshipRecord = null): string | array | null
{
$color = $this->evaluate($this->color, [
'state' => $state,
]);
$color = $this->evaluateForStateItem($this->color, $state, $relationshipRecord);

if ($color === false) {
return null;
Expand Down
7 changes: 3 additions & 4 deletions packages/tables/src/Columns/Concerns/HasIcon.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use Filament\Support\Enums\IconPosition;
use Filament\Tables\Columns\Column;
use Illuminate\Contracts\Support\Htmlable;
use Illuminate\Database\Eloquent\Model;

trait HasIcon
{
Expand Down Expand Up @@ -55,11 +56,9 @@ public function iconPosition(IconPosition | string | Closure | null $iconPositio
return $this;
}

public function getIcon(mixed $state): string | BackedEnum | Htmlable | null
public function getIcon(mixed $state, ?Model $relationshipRecord = null): string | BackedEnum | Htmlable | null
{
$icon = $this->evaluate($this->icon, [
'state' => $state,
]);
$icon = $this->evaluateForStateItem($this->icon, $state, $relationshipRecord);

if ($icon === false) {
return null;
Expand Down
Loading