Flight Active Record
액티브 레코드는 데이터베이스 엔티티를 PHP 객체에 매핑하는 것입니다. 간단히 말해, 데이터베이스에 users 테이블이 있으면 테이블의 행을 코드베이스의 User 클래스와 $user 객체로 "번역"할 수 있습니다. 기본 예제를 참조하세요.
GitHub의 저장소를 보려면 여기를 클릭하세요.
기본 예제
다음과 같은 테이블이 있다고 가정해 보겠습니다:
CREATE TABLE users (
id INTEGER PRIMARY KEY,
name TEXT,
password TEXT
);이제 이 테이블을 나타내는 새 클래스를 설정할 수 있습니다:
/**
* ActiveRecord 클래스는 보통 단수형입니다
*
* 테이블의 속성을 주석으로 여기에 추가하는 것이 강력히 권장됩니다
*
* @property int $id
* @property string $name
* @property string $password
*/
class User extends flight\ActiveRecord {
public function __construct($database_connection)
{
// 이렇게 설정할 수 있습니다
parent::__construct($database_connection, 'users');
// 또는 이렇게
parent::__construct($database_connection, null, [ 'table' => 'users']);
}
}이제 마법이 일어나는 것을 보세요!
// sqlite의 경우
$database_connection = new PDO('sqlite:test.db'); // 이것은 예제일 뿐입니다. 실제 데이터베이스 연결을 사용할 가능성이 큽니다
// mysql의 경우
$database_connection = new PDO('mysql:host=localhost;dbname=test_db&charset=utf8bm4', 'username', 'password');
// 또는 mysqli
$database_connection = new mysqli('localhost', 'username', 'password', 'test_db');
// 또는 객체 기반이 아닌 mysqli 생성
$database_connection = mysqli_connect('localhost', 'username', 'password', 'test_db');
$user = new User($database_connection);
$user->name = 'Bobby Tables';
$user->password = password_hash('some cool password');
$user->insert();
// 또는 $user->save();
echo $user->id; // 1
$user->name = 'Joseph Mamma';
$user->password = password_hash('some cool password again!!!');
$user->insert();
// 여기서 $user->save()를 사용할 수 없으며, 업데이트로 인식할 것입니다!
echo $user->id; // 2새 사용자를 추가하는 것이 이렇게 쉬웠습니다! 이제 데이터베이스에 사용자 행이 있으므로, 이를 어떻게 가져오나요?
$user->find(1); // 데이터베이스에서 id = 1을 찾아 반환합니다.
echo $user->name; // 'Bobby Tables'모든 사용자를 찾고 싶다면?
$users = $user->findAll();특정 조건으로?
$users = $user->like('name', '%mamma%')->findAll();얼마나 재미있나요? 설치하고 시작해 보세요!
설치
Composer로 간단히 설치하세요
composer require flightphp/active-record 사용법
이것은 독립 라이브러리로 사용하거나 Flight PHP Framework와 함께 사용할 수 있습니다. 완전히 당신의 선택입니다.
독립 사용
생성자에 PDO 연결을 전달하기만 하세요.
$pdo_connection = new PDO('sqlite:test.db'); // 이것은 예제일 뿐입니다. 실제 데이터베이스 연결을 사용할 가능성이 큽니다
$User = new User($pdo_connection);생성자에서 항상 데이터베이스 연결을 설정하지 않으려면? 데이터베이스 연결 관리를 참조하세요!
Flight에서 메서드로 등록
Flight PHP Framework를 사용 중이라면, ActiveRecord 클래스를 서비스로 등록할 수 있지만, 꼭 해야 하는 것은 아닙니다.
Flight::register('user', 'User', [ $pdo_connection ]);
// 그런 다음 컨트롤러, 함수 등에서 이렇게 사용할 수 있습니다.
Flight::user()->find(1);runway 메서드
runway는 Flight를 위한 CLI 도구로, 이 라이브러리에 대한 사용자 지정 명령어를 가지고 있습니다.
# 사용법
php runway make:record database_table_name [class_name]
# 예제
php runway make:record users이것은 app/records/ 디렉토리에 UserRecord.php로 새 클래스를 생성하며, 다음과 같은 내용을 포함합니다:
<?php
declare(strict_types=1);
namespace app\records;
/**
* users 테이블을 위한 ActiveRecord 클래스.
* @link https://docs.flightphp.com/awesome-plugins/active-record
*
* @property int $id
* @property string $username
* @property string $email
* @property string $password_hash
* @property string $created_dt
*/
class UserRecord extends \flight\ActiveRecord
{
/**
* @var array $relations 모델의 관계 설정
* https://docs.flightphp.com/awesome-plugins/active-record#relationships
*/
protected array $relations = [
// 'relation_name' => [ self::HAS_MANY, 'RelatedClass', 'foreign_key' ],
];
/**
* 생성자
* @param mixed $databaseConnection 데이터베이스 연결
*/
public function __construct($databaseConnection)
{
parent::__construct($databaseConnection, 'users');
}
}CRUD 함수
find($id = null) : boolean|ActiveRecord
하나의 레코드를 찾아 현재 객체에 할당합니다. $id를 전달하면 해당 값으로 기본 키를 조회합니다. 아무것도 전달하지 않으면 테이블의 첫 번째 레코드를 찾습니다.
또한 테이블을 쿼리하기 위해 다른 도우미 메서드를 전달할 수 있습니다.
// 사전 조건으로 레코드 찾기
$user->notNull('password')->orderBy('id DESC')->find();
// 특정 id로 레코드 찾기
$id = 123;
$user->find($id);findAll(): array<int,ActiveRecord>
지정된 테이블의 모든 레코드를 찾습니다.
$user->findAll();isHydrated(): boolean (v0.4.0)
현재 레코드가 데이터베이스에서 로드(hydrated)되었는지 true를 반환합니다.
$user->find(1);
// 데이터가 있는 레코드가 발견되면...
$user->isHydrated(); // trueinsert(): boolean|ActiveRecord
현재 레코드를 데이터베이스에 삽입합니다.
$user = new User($pdo_connection);
$user->name = 'demo';
$user->password = md5('demo');
$user->insert();텍스트 기반 기본 키
텍스트 기반 기본 키(예: UUID)가 있으면, 삽입 전에 기본 키 값을 두 가지 방법 중 하나로 설정할 수 있습니다.
$user = new User($pdo_connection, [ 'primaryKey' => 'uuid' ]);
$user->uuid = 'some-uuid';
$user->name = 'demo';
$user->password = md5('demo');
$user->insert(); // 또는 $user->save();또는 이벤트를 통해 기본 키를 자동으로 생성할 수 있습니다.
class User extends flight\ActiveRecord {
public function __construct($database_connection)
{
parent::__construct($database_connection, 'users', [ 'primaryKey' => 'uuid' ]);
// 위 배열 대신 이렇게 기본 키를 설정할 수도 있습니다.
$this->primaryKey = 'uuid';
}
protected function beforeInsert(self $self) {
$self->uuid = uniqid(); // 또는 고유 ID를 생성하는 방법에 따라
}
}삽입 전에 기본 키를 설정하지 않으면 rowid로 설정되고 데이터베이스가 생성하지만, 테이블에 해당 필드가 없으면 지속되지 않습니다. 따라서 이벤트를 사용해 자동으로 처리하는 것이 권장됩니다.
update(): boolean|ActiveRecord
현재 레코드를 데이터베이스에 업데이트합니다.
$user->greaterThan('id', 0)->orderBy('id desc')->find();
$user->email = 'test@example.com';
$user->update();save(): boolean|ActiveRecord
현재 레코드를 데이터베이스에 삽입하거나 업데이트합니다. 레코드에 id가 있으면 업데이트하고, 없으면 삽입합니다.
$user = new User($pdo_connection);
$user->name = 'demo';
$user->password = md5('demo');
$user->save();참고: 클래스에 관계가 정의되어 있으면, 정의되고 인스턴스화된 관계 중 업데이트할 더티 데이터가 있는 경우 재귀적으로 저장합니다. (v0.4.0 이상)
delete(): boolean
현재 레코드를 데이터베이스에서 삭제합니다.
$user->gt('id', 0)->orderBy('id desc')->find();
$user->delete();사전에 검색을 실행하여 여러 레코드를 삭제할 수도 있습니다.
$user->like('name', 'Bob%')->delete();dirty(array $dirty = []): ActiveRecord
더티 데이터는 레코드에서 변경된 데이터를 가리킵니다.
$user->greaterThan('id', 0)->orderBy('id desc')->find();
// 이 시점에서 아무것도 "더티"하지 않습니다.
$user->email = 'test@example.com'; // 이제 이메일이 변경되어 "더티"로 간주됩니다.
$user->update();
// 이제 업데이트되어 데이터베이스에 지속되었으므로 더티 데이터가 없습니다
$user->password = password_hash()'newpassword'); // 이제 이것이 더티입니다
$user->dirty(); // 아무것도 전달하지 않으면 모든 더티 항목을 지웁니다.
$user->update(); // 아무것도 업데이트되지 않습니다. 더티로 캡처된 것이 없기 때문입니다.
$user->dirty([ 'name' => 'something', 'password' => password_hash('a different password') ]);
$user->update(); // 이름과 비밀번호가 모두 업데이트됩니다.copyFrom(array $data): ActiveRecord (v0.4.0)
dirty() 메서드의 별칭입니다. 무엇을 하는지 더 명확합니다.
$user->copyFrom([ 'name' => 'something', 'password' => password_hash('a different password') ]);
$user->update(); // 이름과 비밀번호가 모두 업데이트됩니다.isDirty(): boolean (v0.4.0)
현재 레코드가 변경되었는지 true를 반환합니다.
$user->greaterThan('id', 0)->orderBy('id desc')->find();
$user->email = 'test@email.com';
$user->isDirty(); // truereset(bool $include_query_data = true): ActiveRecord
현재 레코드를 초기 상태로 재설정합니다. 루프 유형 동작에서 사용하기 좋습니다.
true를 전달하면 현재 객체를 찾는 데 사용된 쿼리 데이터도 재설정합니다 (기본 동작).
$users = $user->greaterThan('id', 0)->orderBy('id desc')->find();
$user_company = new UserCompany($pdo_connection);
foreach($users as $user) {
$user_company->reset(); // 깨끗한 상태로 시작
$user_company->user_id = $user->id;
$user_company->company_id = $some_company_id;
$user_company->insert();
}getBuiltSql(): string (v0.4.1)
find(), findAll(), insert(), update(), 또는 save() 메서드를 실행한 후 생성된 SQL을 가져와 디버깅에 사용할 수 있습니다.
SQL 쿼리 메서드
select(string $field1 [, string $field2 ... ])
테이블의 일부 컬럼만 선택할 수 있습니다 (많은 컬럼이 있는 넓은 테이블에서 더 성능이 좋습니다)
$user->select('id', 'name')->find();from(string $table)
기술적으로 다른 테이블을 선택할 수도 있습니다! 왜 안 되나요?!
$user->select('id', 'name')->from('user')->find();join(string $table_name, string $join_condition)
데이터베이스의 다른 테이블에 조인할 수도 있습니다.
$user->join('contacts', 'contacts.user_id = users.id')->find();where(string $where_conditions)
사용자 지정 where 인수를 설정할 수 있습니다 (이 where 문에서 params를 설정할 수 없습니다)
$user->where('id=1 AND name="demo"')->find();보안 주의 - $user->where("id = '{$id}' AND name = '{$name}'")->find();처럼 할 수 있지만, 절대 이렇게 하지 마세요!!! 이것은 SQL 인젝션 공격에 취약합니다. 온라인에 많은 기사가 있습니다. "sql injection attacks php"를 Google하면 이 주제에 대한 많은 기사를 찾을 수 있습니다. 이 라이브러리에서 이를 처리하는 올바른 방법은 where() 메서드 대신 $user->eq('id', $id)->eq('name', $name)->find();처럼 하는 것입니다. 반드시 이렇게 해야 한다면, PDO 라이브러리의 $pdo->quote($var)를 사용해 이스케이프하세요. quote()를 사용한 후에만 where() 문에서 사용할 수 있습니다.
group(string $group_by_statement)/groupBy(string $group_by_statement)
특정 조건으로 결과를 그룹화합니다.
$user->select('COUNT(*) as count')->groupBy('name')->findAll();order(string $order_by_statement)/orderBy(string $order_by_statement)
반환된 쿼리를 특정 방식으로 정렬합니다.
$user->orderBy('name DESC')->find();limit(string $limit)/limit(int $offset, int $limit)
반환되는 레코드 수를 제한합니다. 두 번째 int가 주어지면 SQL처럼 offset, limit이 됩니다.
$user->orderby('name DESC')->limit(0, 10)->findAll();WHERE 조건
equal(string $field, mixed $value) / eq(string $field, mixed $value)
Where field = $value
$user->eq('id', 1)->find();notEqual(string $field, mixed $value) / ne(string $field, mixed $value)
Where field <> $value
$user->ne('id', 1)->find();isNull(string $field)
Where field IS NULL
$user->isNull('id')->find();isNotNull(string $field) / notNull(string $field)
Where field IS NOT NULL
$user->isNotNull('id')->find();greaterThan(string $field, mixed $value) / gt(string $field, mixed $value)
Where field > $value
$user->gt('id', 1)->find();lessThan(string $field, mixed $value) / lt(string $field, mixed $value)
Where field < $value
$user->lt('id', 1)->find();greaterThanOrEqual(string $field, mixed $value) / ge(string $field, mixed $value) / gte(string $field, mixed $value)
Where field >= $value
$user->ge('id', 1)->find();lessThanOrEqual(string $field, mixed $value) / le(string $field, mixed $value) / lte(string $field, mixed $value)
Where field <= $value
$user->le('id', 1)->find();like(string $field, mixed $value) / notLike(string $field, mixed $value)
Where field LIKE $value 또는 field NOT LIKE $value
$user->like('name', 'de')->find();in(string $field, array $values) / notIn(string $field, array $values)
Where field IN($value) 또는 field NOT IN($value)
$user->in('id', [1, 2])->find();between(string $field, array $values)
Where field BETWEEN $value AND $value1
$user->between('id', [1, 2])->find();OR 조건
조건을 OR 문으로 감쌀 수 있습니다. startWrap()와 endWrap() 메서드를 사용하거나 필드와 값 다음에 조건의 3번째 매개변수를 채워서 합니다.
// 방법 1
$user->eq('id', 1)->startWrap()->eq('name', 'demo')->or()->eq('name', 'test')->endWrap('OR')->find();
// 이는 `id = 1 AND (name = 'demo' OR name = 'test')`로 평가됩니다
// 방법 2
$user->eq('id', 1)->eq('name', 'demo', 'OR')->find();
// 이는 `id = 1 OR name = 'demo'`로 평가됩니다관계
이 라이브러스를 사용해 여러 종류의 관계를 설정할 수 있습니다. 테이블 간 one->many 및 one->one 관계를 설정할 수 있습니다. 이는 클래스에서 약간의 추가 설정이 필요합니다.
$relations 배열 설정은 어렵지 않지만, 올바른 구문을 추측하는 것은 혼란스러울 수 있습니다.
protected array $relations = [
// 키 이름을 원하는 대로 지정할 수 있습니다. ActiveRecord 이름이 좋습니다. 예: user, contact, client
'user' => [
// 필수
// self::HAS_MANY, self::HAS_ONE, self::BELONGS_TO
self::HAS_ONE, // 이는 관계 유형입니다
// 필수
'Some_Class', // 이는 참조할 "다른" ActiveRecord 클래스입니다
// 필수
// 관계 유형에 따라 다름
// self::HAS_ONE = 조인 참조 외래 키
// self::HAS_MANY = 조인 참조 외래 키
// self::BELONGS_TO = 조인 참조 로컬 키
'local_or_foreign_key',
// 참고로, 이는 "다른" 모델의 기본 키에만 조인됩니다
// 선택
[ 'eq' => [ 'client_id', 5 ], 'select' => 'COUNT(*) as count', 'limit' 5 ], // 관계 조인 시 원하는 추가 조건
// $record->eq('client_id', 5)->select('COUNT(*) as count')->limit(5))
// 선택
'back_reference_name' // 이 관계를 다시 자신으로 백 참조하려면 예: $user->contact->user;
];
]class User extends ActiveRecord{
protected array $relations = [
'contacts' => [ self::HAS_MANY, Contact::class, 'user_id' ],
'contact' => [ self::HAS_ONE, Contact::class, 'user_id' ],
];
public function __construct($database_connection)
{
parent::__construct($database_connection, 'users');
}
}
class Contact extends ActiveRecord{
protected array $relations = [
'user' => [ self::BELONGS_TO, User::class, 'user_id' ],
'user_with_backref' => [ self::BELONGS_TO, User::class, 'user_id', [], 'contact' ],
];
public function __construct($database_connection)
{
parent::__construct($database_connection, 'contacts');
}
}이제 참조가 설정되었으므로 매우 쉽게 사용할 수 있습니다!
$user = new User($pdo_connection);
// 가장 최근 사용자 찾기.
$user->notNull('id')->orderBy('id desc')->find();
// 관계를 사용해 연락처 가져오기:
foreach($user->contacts as $contact) {
echo $contact->id;
}
// 또는 반대로 할 수 있습니다.
$contact = new Contact();
// 하나의 연락처 찾기
$contact->find();
// 관계를 사용해 사용자 가져오기:
echo $contact->user->name; // 이는 사용자 이름입니다꽤 멋지지 않나요?
Eager Loading
개요
Eager loading은 관계를 미리 로드하여 N+1 쿼리 문제를 해결합니다. 각 레코드의 관계에 대해 별도의 쿼리를 실행하는 대신, 관계당 하나의 추가 쿼리로 모든 관련 데이터를 가져옵니다.
참고: Eager loading은 v0.7.0 이상에서만 사용할 수 있습니다.
기본 사용법
with() 메서드를 사용해 eager load할 관계를 지정하세요:
// N+1 대신 2개의 쿼리로 사용자와 연락처 로드
$users = $user->with('contacts')->findAll();
foreach ($users as $u) {
foreach ($u->contacts as $contact) {
echo $contact->email; // 추가 쿼리 없음!
}
}다중 관계
한 번에 여러 관계 로드:
$users = $user->with(['contacts', 'profile', 'settings'])->findAll();관계 유형
HAS_MANY
// 각 사용자에 대한 모든 연락처 eager load
$users = $user->with('contacts')->findAll();
foreach ($users as $u) {
// $u->contacts는 이미 배열로 로드됨
foreach ($u->contacts as $contact) {
echo $contact->email;
}
}HAS_ONE
// 각 사용자에 대한 하나의 연락처 eager load
$users = $user->with('contact')->findAll();
foreach ($users as $u) {
// $u->contact는 이미 객체로 로드됨
echo $u->contact->email;
}BELONGS_TO
// 모든 연락처에 대한 부모 사용자 eager load
$contacts = $contact->with('user')->findAll();
foreach ($contacts as $c) {
// $c->user는 이미 로드됨
echo $c->user->name;
}find()와 함께
Eager loading은 findAll() 및 find() 와 모두 작동합니다:
$user = $user->with('contacts')->find(1);
// 사용자와 모든 연락처가 2개의 쿼리로 로드됨성능 이점
Eager loading 없이 (N+1 문제):
$users = $user->findAll(); // 1 쿼리
foreach ($users as $u) {
$contacts = $u->contacts; // N 쿼리 (사용자당 하나!)
}
// 총: 1 + N 쿼리Eager loading과 함께:
$users = $user->with('contacts')->findAll(); // 총 2 쿼리
foreach ($users as $u) {
$contacts = $u->contacts; // 추가 쿼리 0!
}
// 총: 2 쿼리 (사용자 1 + 모든 연락처 1)10명의 사용자에 대해 쿼리를 11개에서 2개로 줄여 82% 감소!
중요한 주의사항
- Eager loading은 완전히 선택적입니다 - lazy loading은 이전처럼 작동합니다
- 이미 로드된 관계는 자동으로 건너뜁니다
- 백 참조는 eager loading과 작동합니다
- 관계 콜백은 eager loading 중 존중됩니다
제한사항
- 중첩 eager loading (예: with(['contacts.addresses']) )은 현재 지원되지 않습니다
- 클로저를 통한 eager load 제약은 이 버전에서 지원되지 않습니다
사용자 지정 데이터 설정
때때로 ActiveRecord에 고유한 것을 첨부해야 할 수 있습니다. 예를 들어 템플릿에 전달될 객체에 간단히 첨부할 수 있는 사용자 지정 계산입니다.
setCustomData(string $field, mixed $value)
setCustomData() 메서드로 사용자 지정 데이터를 첨부하세요.
$user->setCustomData('page_view_count', $page_view_count);그런 다음 일반 객체 속성처럼 참조하세요.
echo $user->page_view_count;이벤트
이 라이브러리의 또 다른 멋진 기능은 이벤트에 관한 것입니다. 이벤트는 호출하는 특정 메서드에 기반해 특정 시점에 트리거됩니다. 데이터를 자동으로 설정하는 데 매우 유용합니다.
onConstruct(ActiveRecord $ActiveRecord, array &config)
기본 연결을 설정해야 할 때 매우 유용합니다.
// index.php 또는 bootstrap.php
Flight::register('db', 'PDO', [ 'sqlite:test.db' ]);
//
//
//
// User.php
class User extends flight\ActiveRecord {
protected function onConstruct(self $self, array &$config) { // & 참조를 잊지 마세요
// 연결을 자동으로 설정하려면 이렇게 할 수 있습니다
$config['connection'] = Flight::db();
// 또는 이렇게
$self->transformAndPersistConnection(Flight::db());
// 테이블 이름도 이렇게 설정할 수 있습니다.
$config['table'] = 'users';
}
}beforeFind(ActiveRecord $ActiveRecord)
각 쿼리 조작이 필요할 때만 유용할 것입니다.
class User extends flight\ActiveRecord {
public function __construct($database_connection)
{
parent::__construct($database_connection, 'users');
}
protected function beforeFind(self $self) {
// id >= 0을 항상 실행하려면
$self->gte('id', 0);
}
}afterFind(ActiveRecord $ActiveRecord)
이 레코드가 가져올 때마다 항상 로직을 실행해야 할 때 더 유용할 것입니다. 무언가를 복호화해야 하나요? 매번 사용자 지정 카운트 쿼리를 실행해야 하나요 (성능이 좋지 않지만 어쨌든)?
class User extends flight\ActiveRecord {
public function __construct($database_connection)
{
parent::__construct($database_connection, 'users');
}
protected function afterFind(self $self) {
// 무언가 복호화
$self->secret = yourDecryptFunction($self->secret, $some_key);
// 쿼리처럼 사용자 지정 무언가를 저장?
$self->setCustomData('view_count', $self->select('COUNT(*) count')->from('user_views')->eq('user_id', $self->id)['count'];
}
}beforeFindAll(ActiveRecord $ActiveRecord)
각 쿼리 조작이 필요할 때만 유용할 것입니다.
class User extends flight\ActiveRecord {
public function __construct($database_connection)
{
parent::__construct($database_connection, 'users');
}
protected function beforeFindAll(self $self) {
// id >= 0을 항상 실행하려면
$self->gte('id', 0);
}
}afterFindAll(array<int,ActiveRecord> $results)
afterFind()와 유사하지만 모든 레코드에 적용할 수 있습니다!
class User extends flight\ActiveRecord {
public function __construct($database_connection)
{
parent::__construct($database_connection, 'users');
}
protected function afterFindAll(array $results) {
foreach($results as $self) {
// afterFind()처럼 멋진 일을 하세요
}
}
}beforeInsert(ActiveRecord $ActiveRecord)
매번 기본 값을 설정해야 할 때 매우 유용합니다.
class User extends flight\ActiveRecord {
public function __construct($database_connection)
{
parent::__construct($database_connection, 'users');
}
protected function beforeInsert(self $self) {
// 합리적인 기본값 설정
if(!$self->created_date) {
$self->created_date = gmdate('Y-m-d');
}
if(!$self->password) {
$self->password = password_hash((string) microtime(true));
}
}
}afterInsert(ActiveRecord $ActiveRecord)
삽입 후 데이터를 변경해야 하는 사용 사례가 있나요?
class User extends flight\ActiveRecord {
public function __construct($database_connection)
{
parent::__construct($database_connection, 'users');
}
protected function afterInsert(self $self) {
// 당신의 방식대로 하세요
Flight::cache()->set('most_recent_insert_id', $self->id);
// 또는 무엇이든....
}
}beforeUpdate(ActiveRecord $ActiveRecord)
업데이트 시 매번 기본 값을 설정해야 할 때 매우 유용합니다.
class User extends flight\ActiveRecord {
public function __construct($database_connection)
{
parent::__construct($database_connection, 'users');
}
protected function beforeInsert(self $self) {
// 합리적인 기본값 설정
if(!$self->updated_date) {
$self->updated_date = gmdate('Y-m-d');
}
}
}afterUpdate(ActiveRecord $ActiveRecord)
업데이트 후 데이터를 변경해야 하는 사용 사례가 있나요?
class User extends flight\ActiveRecord {
public function __construct($database_connection)
{
parent::__construct($database_connection, 'users');
}
protected function afterInsert(self $self) {
// 당신의 방식대로 하세요
Flight::cache()->set('most_recently_updated_user_id', $self->id);
// 또는 무엇이든....
}
}beforeSave(ActiveRecord $ActiveRecord)/afterSave(ActiveRecord $ActiveRecord)
삽입 또는 업데이트 시 이벤트가 발생하기를 원할 때 유용합니다. 긴 설명은 생략하겠지만, 무엇인지 추측할 수 있을 것입니다.
class User extends flight\ActiveRecord {
public function __construct($database_connection)
{
parent::__construct($database_connection, 'users');
}
protected function beforeSave(self $self) {
$self->last_updated = gmdate('Y-m-d H:i:s');
}
}beforeDelete(ActiveRecord $ActiveRecord)/afterDelete(ActiveRecord $ActiveRecord)
여기서 무엇을 하고 싶은지 모르겠지만, 판단하지 않습니다! 해보세요!
class User extends flight\ActiveRecord {
public function __construct($database_connection)
{
parent::__construct($database_connection, 'users');
}
protected function beforeDelete(self $self) {
echo 'He was a brave soldier... :cry-face:';
}
}데이터베이스 연결 관리
이 라이브러리를 사용할 때 데이터베이스 연결을 여러 방식으로 설정할 수 있습니다. 생성자에서 연결을 설정하거나, $config['connection'] 설정 변수로 설정하거나 setDatabaseConnection() (v0.4.1)을 사용할 수 있습니다.
$pdo_connection = new PDO('sqlite:test.db'); // 예제용
$user = new User($pdo_connection);
// 또는
$user = new User(null, [ 'connection' => $pdo_connection ]);
// 또는
$user = new User();
$user->setDatabaseConnection($pdo_connection);액티브 레코드를 호출할 때마다 항상 $database_connection을 설정하지 않으려면, 이를 피할 방법이 있습니다!
// index.php 또는 bootstrap.php
// Flight에서 등록된 클래스로 설정
Flight::register('db', 'PDO', [ 'sqlite:test.db' ]);
// User.php
class User extends flight\ActiveRecord {
public function __construct(array $config = [])
{
$database_connection = $config['connection'] ?? Flight::db();
parent::__construct($database_connection, 'users', $config);
}
}
// 이제 인수 불필요!
$user = new User();참고: 단위 테스트를 계획 중이라면, 이 방식은 단위 테스트에 약간의 도전을 추가할 수 있지만,
setDatabaseConnection()또는$config['connection']으로 연결을 주입할 수 있으므로 전체적으로 나쁘지 않습니다.
데이터베이스 연결을 새로 고쳐야 할 때, 예를 들어 장기 실행 CLI 스크립트를 실행 중이고 연결을 주기적으로 새로 고쳐야 한다면, $your_record->setDatabaseConnection($pdo_connection)으로 재설정할 수 있습니다.
기여
참여해 주세요. :D
설정
기여할 때 composer test-coverage를 실행해 100% 테스트 커버리지를 유지하세요 (이것은 진짜 단위 테스트 커버리지가 아니라 통합 테스트에 가깝습니다).
또한 composer beautify와 composer phpcs를 실행해 린팅 오류를 수정하세요.
라이선스
MIT