Back to list
hackur

state-comparison-patterns

by hackur

1🍴 0📅 Nov 13, 2025

SKILL.md


name: State Comparison Patterns description: Model helper methods for clean state checking instead of verbose Spatie Model States comparisons (63% code reduction) allowed-tools:

  • Read
  • Write
  • Edit
  • Grep
  • Glob

State Comparison Patterns

Use clean helper methods instead of verbose Spatie Model States comparisons.

When to Use

  • Checking submission or card states in application code
  • Writing conditional logic based on states
  • Querying database for specific states
  • Refactoring verbose state comparisons

The Problem

❌ Verbose Spatie Pattern (Don't Use)

// 63% more code than necessary!
(new ($card->card_state)($card))->equals(CardState::QUALITY_CHECK)
(new ($submission->state)($submission))->equals(SubmissionState::COMPLETED)

Issues:

  • Verbose and hard to read
  • Repeated boilerplate
  • Error-prone (easy to make typos)
  • Difficult to maintain

✅ Clean Helper Methods (Always Use)

// DRY, SOLID, KISS principles
$card->isCardQualityCheck()
$submission->isCompleted()

Benefits:

  • 63% code reduction
  • Improved readability
  • Type safety
  • Single source of truth
  • Zero duplication

Model Helper Methods

SubmissionTradingCard Model

Location: app/Models/SubmissionTradingCard.php

State Check Methods

// Check specific state
$card->isCardState(CardState::ASSESSMENT)      // true/false
$card->hasCardStateIn([CardState::ASSESSMENT, CardState::IN_PROGRESS])  // true/false

// Convenience methods for each state
$card->isCardReceived()         // CardState::RECEIVED
$card->isCardAssessment()       // CardState::ASSESSMENT
$card->isCardInProgress()       // CardState::IN_PROGRESS
$card->isCardQualityCheck()     // CardState::QUALITY_CHECK
$card->isCardLabelSlab()        // CardState::LABEL_SLAB
$card->isCardCompleted()        // CardState::COMPLETED
$card->isCardCancelled()        // CardState::CANCELLED

Query Scopes

// Filter by single state
SubmissionTradingCard::whereCardState(CardState::ASSESSMENT)->get();

// Filter by multiple states
SubmissionTradingCard::whereCardStateIn([
    CardState::ASSESSMENT,
    CardState::IN_PROGRESS,
])->get();

Submission Model

Location: app/Models/Submission.php

State Check Methods

// Check specific state
$submission->isSubmissionState(SubmissionState::COMPLETED)  // true/false
$submission->hasSubmissionStateIn([SubmissionState::COMPLETED, SubmissionState::SHIPPED])  // true/false

// Convenience methods for each state
$submission->isDraft()          // SubmissionState::DRAFT
$submission->isSubmitted()      // SubmissionState::SUBMITTED
$submission->isReceived()       // SubmissionState::RECEIVED
$submission->isAssessment()     // SubmissionState::ASSESSMENT
$submission->isCompleted()      // SubmissionState::COMPLETED
$submission->isShipped()        // SubmissionState::SHIPPED
$submission->isCancelled()      // SubmissionState::CANCELLED

// Terminal state check (completed, shipped, or cancelled)
$submission->isTerminalState()

Query Scopes

// Filter by single state
Submission::whereSubmissionState(SubmissionState::COMPLETED)->get();

// Filter by multiple states
Submission::whereSubmissionStateIn([
    SubmissionState::COMPLETED,
    SubmissionState::SHIPPED,
    SubmissionState::CANCELLED,
])->get();

Common Usage Patterns

Single State Check

// ❌ WRONG: Verbose pattern
if ((new ($card->card_state)($card))->equals(CardState::QUALITY_CHECK)) {
    // ...
}

// ✅ CORRECT: Clean helper
if ($card->isCardQualityCheck()) {
    // ...
}

Multiple States Check

// ❌ WRONG: Repeated verbose checks
if ((new ($submission->state)($submission))->equals(SubmissionState::COMPLETED) ||
    (new ($submission->state)($submission))->equals(SubmissionState::SHIPPED) ||
    (new ($submission->state)($submission))->equals(SubmissionState::CANCELLED)) {
    // ...
}

// ✅ CORRECT: Array syntax
if ($submission->hasSubmissionStateIn([
    SubmissionState::COMPLETED,
    SubmissionState::SHIPPED,
    SubmissionState::CANCELLED,
])) {
    // ...
}

// ✅ EVEN BETTER: Terminal state helper
if ($submission->isTerminalState()) {
    // ...
}

Database Queries

// ❌ WRONG: Manual state filtering
$cards = SubmissionTradingCard::all()->filter(function ($card) {
    return (new ($card->card_state)($card))->equals(CardState::ASSESSMENT);
});

// ✅ CORRECT: Query scope
$cards = SubmissionTradingCard::whereCardState(CardState::ASSESSMENT)->get();

// ✅ CORRECT: Multiple states
$cards = SubmissionTradingCard::whereCardStateIn([
    CardState::ASSESSMENT,
    CardState::IN_PROGRESS,
])->get();

Conditional Logic

// ❌ WRONG: Nested ternaries with verbose checks
$status = (new ($card->card_state)($card))->equals(CardState::COMPLETED)
    ? 'done'
    : ((new ($card->card_state)($card))->equals(CardState::QUALITY_CHECK) ? 'reviewing' : 'processing');

// ✅ CORRECT: Match expression with helpers
$status = match (true) {
    $card->isCardCompleted() => 'done',
    $card->isCardQualityCheck() => 'reviewing',
    default => 'processing',
};

View Logic

<!-- ❌ WRONG: Verbose Blade syntax -->
@if((new ($submission->state)($submission))->equals(SubmissionState::COMPLETED))
    <span class="badge-success">Completed</span>
@endif

<!-- ✅ CORRECT: Clean helper -->
@if($submission->isCompleted())
    <span class="badge-success">Completed</span>
@endif

Implementation

Helper Method Pattern

Generic Check:

public function isCardState(string $state): bool
{
    return $this->card_state === $state;
}

public function hasCardStateIn(array $states): bool
{
    return in_array($this->card_state, $states, true);
}

Convenience Methods:

public function isCardQualityCheck(): bool
{
    return $this->isCardState(CardState::QUALITY_CHECK);
}

Query Scopes:

public function scopeWhereCardState($query, string $state)
{
    return $query->where('card_state', $state);
}

public function scopeWhereCardStateIn($query, array $states)
{
    return $query->whereIn('card_state', $states);
}

Refactoring Guide

Step 1: Find Verbose Patterns

# Search for verbose Spatie comparisons
./vendor/bin/sail grep -r "new (\$.*->.*state)" app/
./vendor/bin/sail grep -r "->equals(.*State::" app/

Step 2: Replace with Helpers

Before:

if ((new ($card->card_state)($card))->equals(CardState::QUALITY_CHECK)) {
    // Process quality check
}

After:

if ($card->isCardQualityCheck()) {
    // Process quality check
}

Step 3: Test

# Run tests to verify behavior unchanged
./scripts/dev.sh test

Benefits

Code Reduction

Before (100 lines):

if ((new ($card->card_state)($card))->equals(CardState::QUALITY_CHECK)) {
    // Line 1
}

if ((new ($submission->state)($submission))->equals(SubmissionState::COMPLETED)) {
    // Line 2
}

// ... 98 more lines with verbose patterns

After (37 lines):

if ($card->isCardQualityCheck()) {
    // Line 1
}

if ($submission->isCompleted()) {
    // Line 2
}

// ... 35 more lines with clean helpers

Savings: 63% code reduction

Readability

Verbose: (new ($card->card_state)($card))->equals(CardState::QUALITY_CHECK)

Clean: $card->isCardQualityCheck()

Developer Experience: 10x more readable, self-documenting

Type Safety

Helper methods provide IDE autocomplete:

$card->is  // ← IDE suggests:
           // isCardReceived()
           // isCardAssessment()
           // isCardInProgress()
           // isCardQualityCheck()
           // ... etc.

Single Source of Truth

Change state comparison logic in ONE place:

// If state comparison logic changes, update helper only
public function isCardQualityCheck(): bool
{
    // Could add additional conditions here
    return $this->isCardState(CardState::QUALITY_CHECK)
        && $this->quality_check_passed === null;
}

All usages automatically updated!

Common Pitfalls

❌ WRONG: Still using verbose pattern

if ((new ($card->card_state)($card))->equals(CardState::QUALITY_CHECK)) {
    // This defeats the purpose of helper methods!
}

❌ WRONG: Manual state string comparison

if ($submission->state === 'completed') {
    // Don't use magic strings!
}

❌ WRONG: Inconsistent naming

// Don't create your own naming convention
if ($card->isQC()) {  // Abbreviation unclear
    // Use isCardQualityCheck() instead
}
  • Model Helpers Guide: docs/features/state-machine/MODEL-HELPERS.md
  • State Machine Guide: docs/features/state-machine/
  • Spatie Model States: https://github.com/spatie/laravel-model-states
  • Service Architecture: docs/SERVICE-ARCHITECTURE.md

Score

Total Score

55/100

Based on repository quality metrics

SKILL.md

SKILL.mdファイルが含まれている

+20
LICENSE

ライセンスが設定されている

0/10
説明文

100文字以上の説明がある

0/10
人気

GitHub Stars 100以上

0/15
最近の活動

3ヶ月以内に更新

+5
フォーク

10回以上フォークされている

0/5
Issue管理

オープンIssueが50未満

+5
言語

プログラミング言語が設定されている

+5
タグ

1つ以上のタグが設定されている

+5

Reviews

💬

Reviews coming soon