코드이그나이터4는 기본 모델 외에 자동으로 생성,수정,삭제 시간을 넣어주는 기능이 있습니다. 또한 삭제를 컨트롤하는 소프트 딜리트(soft delete)도 있죠. 기본 모델보다 조금 더 풍부한 기능을 사용해 보겠습니다.
본 예제는 https://github.com/koeunyeon/ci4/tree/model-rich-model에 있습니다.
마이그레이션 부분을 따라하셨다면 이미 sample_rich
테이블이 생성되어 있을 겁니다. 만약 없거나, 따로 데이터베이스에서 만드시려면 아래의 쿼리를 입력하세요.
-- auto-generated definition
create table sample_rich
(
sample_rich_id bigint unsigned auto_increment
primary key,
name varchar(40) not null,
age int null,
created_at varchar(25) not null,
updated_at varchar(25) not null,
deleted_at varchar(25) null
)
charset = utf8;
/app/Models
디렉토리 아래에 RichModel.php
파일을 생성하고 아래의 내용으로 대체합니다.
/app/Models/RichModel.php
<?php
namespace App\Models;
use CodeIgniter\Model;
class RichModel extends Model
{
protected $table = 'sample_rich';
protected $allowedFields = ['name','age'];
protected $primaryKey = "sample_rich_id";
protected $useSoftDeletes = true; // (1)
protected $useTimestamps = true; // (2)
}
(1) 소프트 딜리트(soft delete)를 사용할 지 여부를 결정합니다. 기본값은 false
입니다. 소프트 딜리트를 사용하면 데이터가 실제로 삭제되는 것이 아니라 데이터베이스에 삭제되었다고 표시만 됩니다.
소프트 딜리트를 사용하려면 $deletedField
멤버 변수가 선언되어 있어야 합니다. 다행히도 CodeIgniter\Model
클래스에는 이미 $deletedField = 'deleted_at'
멤버 변수가 선언되어 있으므로 데이터베이스 열 이름이 deleted_at
이라면 직접 선언할 필요는 없습니다.
(2) 자동 시간대를 사용할 지 여부를 나타냅니다. 기본값은 false
입니다.
자동 시간대를 사용하려면 $createdField
멤버변수와 $updatedField
멤버변수가 필요합니다. 선언하지 않으면 각각 부모 클래스의 정의에 따라 created_at
과 updated_at
을 사용합니다.
테스트를 위한 컨트롤러 클래스를 작성하겠습니다. /app/Controllers
디렉토리 아래에 Rich.php
파일을 생성하고 아래의 내용으로 대체합니다.
/app/Controllers/Rich.php
<?php
namespace App\Controllers;
use App\Models\RichModel;
class Rich extends BaseController
{
public function create()
{
$richModel = new RichModel();
// (1)
$last_insert_id = $richModel->insert([
'name' => 'rich',
'age' => 22
]);
$find_result = $richModel->find($last_insert_id);
return $this->response->setJSON($find_result);
}
public function save($id, $name, $age) // (2)
{
$richModel = new RichModel();
$richData = $richModel->find($id);
if ($richData === null) { // (3)
$richData = [];
}
// (4)
$richData['name'] = $name;
$richData['age'] = $age;
$richModel->save($richData); // (5)
$last_insert_id = $richModel->getInsertID(); // (6)
if ($last_insert_id == null) { // (7)
$last_insert_id = $richData['sample_rich_id'];
}
$last_insert_data = $richModel->find($last_insert_id); // (8)
return $this->response->setJSON($last_insert_data);
}
public function remove($id)
{
$richModel = new RichModel();
$richModel->delete($id); // (9)
$select_result_before = $richModel->find($id); // (10)
$with_deleted_result_before = $richModel->withDeleted()->find($id); // (11)
$richModel->purgeDeleted(); // (12)
$select_result_after = $richModel->find($id); // (13)
$with_deleted_result_after = $richModel->withDeleted()->find($id); // (14)
return $this->response->setJSON([ // (15)
'select_result_before' => $select_result_before,
'with_deleted_result_before' => $with_deleted_result_before,
'select_result_after' => $select_result_after,
'with_deleted_result_after' => $with_deleted_result_after,
]);
}
}
(1) 샘플 데이터를 입력합니다. 데이터는 name
과 age
두개를 세팅했습니다.
브라우저로 http://localhost:8080/rich/create 에 접속해서 결과를 확인하겠습니다.
{
"sample_rich_id": "1",
"name": "rich",
"age": "22",
"created_at": "2021-02-02 00:09:56",
"updated_at": "2021-02-02 00:09:56",
"deleted_at": null
}
created_at
, updated_at
, 필드는 데이터를 설정하지 않았음에도 불구하고 데이터가 입력되어 있는 것을 확인할 수 있습니다.
(2) 데이터를 입력하거나 수정하는 엔드포인트 save
를 만듭니다. 각 파라미터는 주 키(id
), 이름(name
), 나이(age
)를 나타냅니다.
(3) 만약 주 키인 $id
로 조회했을 때 데이터가 없으면 모델은 null
을 반환합니다. 따라서 null
이라면 데이터를 빈 배열로 초기화($richData = [];
) 합니다.
(4) 저장할 데이터를 파라미터로 설정합니다.
(5) 데이터를 저장합니다. richData['sample_rich_id']
가 설정되어 있다면 update
, 아니면 insert
입니다.
(6) 코드이그나이터4에서는 모델의 insert
메소드를 썼을 때 반환값이 마지막 입력된 주 키 입니다. 하지만 save
의 경우에는 반환값이 성공/실패 여부를 나타내는 boolean
타입이므로 만약 save
메소드가 insert
로 작동했다면 반환값만으로는 주 키를 알 수 없게 됩니다.
따라서 마지막 ID를 가져오는 getInsertID()
메소드를 사용합니다. 이 메소드는 update
로 동작했을 때는 null
을 리턴합니다.
(7) $last_insert_id === null
은 save
메소드가 update
로 동작했다는 뜻입니다. 즉 이미 richData
연관배열에 주 키가 설정되어 있다는 뜻이므로 $last_insert_id
변수의 값을 $richData['sample_rich_id']
로 교체합니다.
(8) 마지막으로 생성/수정된 데이터를 조회합니다.
브라우저에서 실행해 보겠습니다. http://localhost:8080/rich/save/1/richmodel/33 주소에 접속해 봅니다.
이미 생성된 데이터가 있을 경우 수정이 일어나므로 created_at
데이터와 updated_at
데이터가 서로 달라야 합니다.
{
"sample_rich_id": "1",
"name": "richmodel",
"age": "33",
"created_at": "2021-02-02 00:09:56",
"updated_at": "2021-02-02 00:20:30",
"deleted_at": null
}
생성인 경우에는 두 시간이 동일합니다. http://localhost:8080/rich/save/2/richmodel2/44 에 접속해 봅시다.
{
"sample_rich_id": "4",
"name": "richmodel2",
"age": "44",
"created_at": "2021-02-02 00:23:03",
"updated_at": "2021-02-02 00:23:03",
"deleted_at": null
}
created_at
데이터와 updated_at
데이터가 동일함을 알 수 있습니다.
한번 http://localhost:8080/rich/save/2/richmodel2/44 요청이 일어나면 이번엔 수정으로 동작하므로 created_at
과 updated_at
이 달라집니다.
{
"sample_rich_id": "5",
"name": "richmodel2",
"age": "44",
"created_at": "2021-02-02 00:47:51",
"updated_at": "2021-02-02 00:47:51",
"deleted_at": null
}
(9) 삭제 엔드포인트를 살펴보겠습니다. 모델에서 $useSoftDeletes = true
로 설정했을 경우 deleted_at
열만 수정됩니다. 다시말해 실제로는 delete
쿼리가 실행되지 않습니다.
(10) 실제로 코드이그나이터4에서 소프트 딜리트를 사용할 경우 조회 쿼리 조건에 deleted_at is not null
을 붙여서 실행됩니다. 따라서 $select_result_before
변수는 null
을 반환합니다.
(11) deleted_at
열을 무시하고 모든 데이터를 가져와야 할 경우도 있을 겁니다. 그럴 때는 withDeleted()
옵션을 줄 수 있습니다. $with_deleted_result_before
변수에는 실제 데이터베이스에 존재하는 데이터라면 deleted_at
열의 null
여부와 무관하게 모든 데이터를 가져올 수 있게 됩니다.
(12) deleted_at
열이 null
이 아닌 모든 데이터를 실제로 삭제합니다. 쿼리로 표현하자면 delete from 테이블 where $deletedField is not null
입니다.
이제 데이터가 모두 삭제되었으므로 withDeleted()
여부에 상관없이 데이터는 조회할 수 없습니다.
(13) **(10)**과 동일한 조회입니다. purgeDeleted()
이후에도 null
을 동일하게 리턴합니다. 다만 $select_result_before
는 "실제로 데이터가 있으나 조회가 되지 않음 것"인데 반해, $select_result_after
는 "실제로 데이터가 없으니까 조회할 수 없음"입니다.
(14) **(11)**과 동일한 조회입니다. 하지만 이번에는 **(11)**과 다르게 null
을 반환하는데, 실제로 데이터가 데이터베이스 테이블에서 삭제되었기 때문입니다.
(15) 결과를 확인하기 위해 모든 변수를 JSON 형식으로 리턴합니다.
http://localhost:8080/rich/remove/1 주소에 접속해서 확인해 봅시다.
{
"select_result_before": null,
"with_deleted_result_before": {
"sample_rich_id": "1",
"name": "richmodel",
"age": "33",
"created_at": "2021-02-02 00:09:56",
"updated_at": "2021-02-02 00:32:03",
"deleted_at": "2021-02-02 00:32:03"
},
"select_result_after": null,
"with_deleted_result_after": null
}
이제 모든 데이터가 삭제되었으므로 http://localhost:8080/rich/remove/1 주소에 접속해서 확인해 보면 아무것도 조회할 수 없음을 볼 수 있습니다.
{
"select_result_before": null,
"with_deleted_result_before": null,
"select_result_after": null,
"with_deleted_result_after": null
}