DatabaseTable

octofox·2021년 6월 7일
0

메모

목록 보기
3/4
<?php
namespace Redbookers; //오토로드는 네임스페이스를 참조합니다. Redbookers 폴더 아래에 위치하기 때문에 네임스페이스를 Redbookers로 작성해야 오토로드에서 호출이 가능합니다

// 해당 클래스는 classes/Insights/InsightsRoutes.php에서 사용됩니다
// 사용자가 url 이동시, 페이지마다 필요한 DB테이블도 달라지기 때문에 url를 다루는 InsightsRoutes.php에서 사용됩니다

class DatabaseTable { 
	// 다른 웹 페이지에서도 사용 가능한 범용 클래스입니다
	// form 태그의 input name을 DB의 컬럼명과 일치해야합니다
	private $pdo;
	private $table;
	private $primaryKey;
	private $className;
	private $constructorArgs;

	public function __construct(\PDO $pdo, string $table, string $primaryKey, string $className = '\stdClass',
	array $constructorArgs = [] )
	{ 
		// 생성자 함수는 DB커넥션, 테이블 이름, 해당 테이블의 메인 인덱스를 명시해 초기화합니다
		// ex) $var = new DatabaseTable($pdo, 'tablename', 'id');
		$this->pdo = $pdo;
		$this->table = $table;
		$this->primaryKey = $primaryKey;
		$this->className = $className;
		$this->constructorArgs = $constructorArgs;
	}

	private function query($sql, $parameters = [])
	{
		// private 키워드는 해당 클래스 외부에서 수정, 접근이 불가합니다
		// query는 내장함수이며 다른 모든 함수의 재료가 됩니다
		$query = $this->pdo->prepare($sql);
		$query->execute($parameters);
		return $query;
	}	

	public function total($fields = null, $value = null)
	{	
		$sql = 'SELECT COUNT(*) FROM `' . $this->table . '`';
		$parameters = [];
		if(!empty($fields)){
			$sql .= 'WHERE' . $fields . '= :value';
			$parameters = ['value' => $value];
		}
		$query = $this->query($sql, $parameters);
		$row = $query->fetch();
		return $row[0];
	}

	public function findAll($orderBy = null, $limit = null, $offset = null)
	{
		$query = 'SELECT * FROM ' . $this->table;
		if($orderBy != null){
			$query .= ' ORDER BY ' . $orderBy;
		}
		if($limit != null){
			$query .= ' LIMIT ' . $limit;
		}
		if($offset != null){
			$query .= ' OFFSET ' . $offset;
		}

		$result = $this->query($query);

		return $result->fetchAll(\PDO::FETCH_CLASS, $this->className, $this->constructorArgs);
	}

	public function findById($value) { // 실패시 false;
		$query = 'SELECT * FROM `' . $this->table . '` WHERE `' . $this->primaryKey . '` = :value';

		$parameters = [
			'value' => $value
		];

		$query = $this->query($query, $parameters);

		return $query->fetchObject($this->className, $this->constructorArgs);
	}

	public function find($column, $value, $orderBy = null, $limit = null, $offset = null)
	{
		$query = 'SELECT * FROM ' . $this->table . ' WHERE ' . $column . ' = :value';

		$parameters = [
			'value' => $value
		];

		if($orderBy != null){
			$query .= ' ORDER BY ' . $orderBy;
		}
		if($limit != null){
			$query .= ' LIMIT ' . $limit;
		}
		if($offset != null){
			$query .= ' OFFSET ' . $offset;
		}

		$query = $this->query($query, $parameters);

		return $query->fetchAll(\PDO::FETCH_CLASS, $this->className, $this->constructorArgs);
	}


	private function insert($fields) // fields는  columnName => value로 이루어진 배열이다
	{
		$query = 'INSERT INTO `' . $this->table . '` (';

		foreach ($fields as $key => $value) { // 쿼리문을 생성하는데 key만 사용한다
			$query .= '`' . $key . '`,';
		}

		$query = rtrim($query, ',');

		$query .= ') VALUES (';


		foreach ($fields as $key => $value) { // 이곳에는 키와 자리 지정자만 생성한다 마찬가지로 value는 사용되지 않는다
			$query .= ':' . $key . ','; 	  // ex) id = :id
											  // 이처럼 자리지정자를 사용하면 sql 인젝션을 막을 수 있다
		}

		$query = rtrim($query, ','); // 마지막 쉼표 제거

		$query .= ')';

		$fields = $this->processDates($fields); // 날짜형식을 고정한다
		
		//echo $query;
		$this->query($query, $fields); // value를 자리 지정자와 bind 하기 위해 다시 fields를 보낸다
	}


	private function update($fields)
	{ // 업데이트 문도 private 선언이된 내장 함수다
		$query = ' UPDATE `' . $this->table .'` SET ';

		foreach ($fields as $key => $value) {
			$query .= '`' . $key . '` = :' . $key . ',';
		}

		$query = rtrim($query, ',');

		$query .= ' WHERE `' . $this->primaryKey . '` = :primaryKey';

		// :primaryKey 변수 설정
		$fields['primaryKey'] = $fields[$this->primaryKey];

		$fields = $this->processDates($fields);

		$this->query($query, $fields);
	}


	public function delete($id )
	{
		$parameters = [':id' => $id];

		$this->query('DELETE FROM `' . $this->table . '` WHERE `' . $this->primaryKey . '` = :id', $parameters);
	}

	public function deleteWhere($column, $value) {
		$query = 'DELETE FROM ' . $this->table . ' WHERE ' . $column . ' = :value';

		$parameters = [
			'value' => $value
		];

		$query = $this->query($query, $parameters);
	}

	private function processDates($fields) // INSERT 되는 시간형식이 통일됩니다.
	{ // 클래스 내부에서만 쓰이기에 private으로 지정됬다
		foreach ($fields as $key => $value) {
			if ($value instanceof DateTime) {
				$fields[$key] = $value->format('Y-m-d H:i:s');
			}
		}

		return $fields;
	}

	// insert와 update가 합해진 함수입니다
	public function save($record)
	{
		// id가 없으면 insert, id가 존재하면 update문을 실행합니다 
		try {
			if ($record[$this->primaryKey] == '') {
				$record[$this->primaryKey] = null;
			}
			$this->insert($record); // id 필드가 존재하는 채로 insert문을 실행하면 오류가 발생합니다
		}
		catch (\PDOException $e) {
			$this->update( $record); // 발생된 오류로 인해 update가 실행됩니다
		}
	}
}
profile
개발자라고 우기는 노답 소년

0개의 댓글