Confluence 에 심각한 보안 취약점이 발견되었으니 사용자분들은 업그레이드 하세요.!
 
1
0
-1

Eloquent 환경에서, A→(hasMany)→B→(hasOne)→C→(hasMany)→D

형태의 모델에 대한 로직을 짜는 도중, A에서 정의된 정보를 토대로 D의 가짜 데이터를 생성해줘야 하는 상황이 발생했습니다.

A가 'numeric', 9 이라는 타입/숫자 라면 C가 소유한 D를 9개의 가짜 모델 인스턴스가 생성되어야 하는 방식이죠. 일단 hasMany 가 withDefault(...) 를 사용하지 못하는 것도 그렇고, 깊이가 존재하는 relationship 에 대해서는 동작하지 않아 withdefault 는 사용할 수 없었습니다.

이렇게 뽑아진 데이터는 이후에 가공만 하고 저장같은 로직을 사용할 일이 없습니다. 다만, Laravel collection 이 주는 이점을 포기하기 싫어서.. 


--- 

/**
 * @propery-read Item[]|Collection $items
 */
class Test extends \Illuminate\Database\Eloquent\Model
{
    //
    public function items()
    {
        return $this->hasMany(Item::class);
    }
}

위 Test class 에 가짜 Items 들을 삽입하고 싶습니다. 실제로는 존재하지 않지만, 채워져있는 데이터가 필요한 상황이라서요. 만약 doctrine 이라면


/**
 * @ORM\Entity
 */
class Test
{
    /**
     * @ORM\OneToMany(targetEntity="Item", mappedBy="test")
     * @var Item[]|ArrayCollection
     */
    protected $items;
	
    /**
     * @param Item $item
     */
    public function addItem(Item $item): void
    {
        if( !$this->items->contains($item) ) {
            $item->setTest($this);
            $this->items->add($item);
        }
    }
}

이 상황에서 DB와 연결 없이 바로 추가할 수 있고, 이 Entity 를 가공해도 실제로는 data class 처럼 처리할 수 있기에, Eloquent 에서 이러한 로직을 어떻게 구현해야 하는가에 대해 의문이 있습니다. Eloquent 에서 Relation에 접근하면

$testModelInstance = new Test();
for ($i = 0; $i < 5; ++$i) {
    $testModelInstance->items->push(...); // 이곳에 new Item() 으로 실제로는 DB에 없는 아이템들을 넣는다.
}


// SELECT ... 
// SELECT ...
// SELECT ...
// SELECT ...
// SELECT ...

가 되어버립니다. Relation 데이터가 없다면 $relations 에 데이터가 들어가질 않는데, 애초에 데이터가 없는 경우에는 이로 인해 with, load 가 동작하지 않은 것으로 판단하여 다시금 쿼리를 발생시키기 때문입니다.

위 코드가 좋다고 말하기도 애매한 것이, Eloquent 와 DB 는 강하게 묶여있고, newModelInstance 를 사용한다 한들 DB 관련 로직을 다 들고 다녀야 하기 때문에 위험하고 (→save(...) 이벤트 발생과 같은 상황)


이 상황에서, Eloquent → data class → 비즈니스 로직

으로 만들면 같은 객체를 가공할 수 있지만, 이런 계층을 따로 두는 경우 결국 DM 처럼 되어버리는 것이 아닌가, 그렇다면 DM 과 유의미한 차이는 무엇인가? 라는 의문이 생깁니다



감사합니다.


    CommentAdd your comment...

    1 answer

    1.  
      1
      0
      -1

      자문자답입니다.

      최선의 방법은 계층간 DTO를 만들어서 가공하는게 좋다고 합니다. 이게 Best practice 인지 알 수가 없어서 이런 이상한 고민까지 도달했던 것인데, 결국 Entity가 되었든 Eloquent model이 되었든 이 경우는 표현 로직에 해당하기에 지양해야 하는 방식이더군요.


      이젠 DTO 네이밍 룰이나 찾아보러 가야겠습니다 ㅋㅋ..

        CommentAdd your comment...