일반적인 유용한 기능
PHP 태그 시스템을 구현하는 방법에 대한 튜토리얼에 오신 것을 환영합니다. 태그는 요즘 시스템에서 공통적인 기능이며 게시물, 제품, 사진, 비디오, 오디오 등을 설명하는 데 사용되는 방법을 거의 볼 수 있습니다…
유사한 태그 시스템을 자신의 프로젝트에 배치하려는 경우 ,이 안내서는 작성 방법에 대한 정확한 단계를 안내합니다. 알아 보려면 계속 읽으십시오!
ⓘ이 튜토리얼의 시작 부분에 모든 소스 코드가 포함 된 zip 파일이 포함되어 있으므로 모든 것을 복사하여 붙여 넣을 필요가 없습니다.
소스 코드 다운로드
먼저 약속 한대로 소스 코드에 대한 다운로드 링크가 있습니다.
소스 코드 다운로드
소스 코드를 다운로드하려면 여기를 클릭하십시오. MIT 라이센스에 따라 릴리스되었으므로 그 위에 빌드하거나 자신의 프로젝트에서 자유롭게 사용하십시오.
폴더
다음은 zip 파일에서 폴더를 구성하는 방법에 대한 간략한 소개입니다.
빠른 시작
개요 및 가정
코드 섹션을 시작하기 전에 먼저 시스템의 개요와 몇 가지 가정을 설명하겠습니다. 따라서 이 안내서에서 무엇을 기대해야 하는지 알고 있습니다.
가정 및 참고 사항
여기에 있는 대부분의 사람들은 이미 기존 시스템을 가지고 있거나 태그 시스템이 독립적 인 시스템으로는 의미가 없습니다. 따라서 우리는 휠을 재발 명하는 대신 게시물, 제품, 이미지 또는 태그를 지정하려는 모든 항목을 다루지 않습니다. 이 가이드는 순전히 태그 만 다룰 것입니다.
또한 순수한 HTML, CSS, Javascript 및 PHP 만 사용합니다. jQuery, Bootstrap, Cake 또는 Symfony와 같은 타사 프레임 워크는 없을 것입니다. 그러면 여러분의 통합이 훨씬 쉬워 질 것입니다.
개요
이 안내서와 시스템에는 3 가지 부분이 있습니다.
데이터베이스
이제 시스템 개요를 다 살펴 봤으므로 데이터베이스 테이블을 작성하여 기초부터 시작하겠습니다.
태그 테이블
CREATE TABLE `tags` ( `post_id` int(11) NOT NULL, `tag` varchar(32) NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=latin1; ALTER TABLE `tags` ADD PRIMARY KEY (`post_id`,`tag`); COMMIT;
Field | Description |
post_id | Primary key. The post ID, or it could be your product ID, image ID, whatever you want to tag. |
tag | Primary key. The tag itself, feel free to change the number of characters if you are expecting very long tags. |
그렇습니다.이 간단한 테이블만 있으면 됩니다.
데모 포스트 테이블
초보자를 위해 완성도를 높이기 위해 태그를 추가 할 게시물 테이블 예입니다. 그러나 실제로 고유 한 고유 ID로 태그를 지정할 수 있습니다.
CREATE TABLE `posts` ( `post_id` int(11) NOT NULL, `post_title` text NOT NULL, `post_txt` text NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=latin1; INSERT INTO `posts` (`post_id`, `post_title`, `post_txt`) VALUES (1, 'Stream of Rainbow', 'Can the predecessor hope the diesel? The unknown bombs whatever buried manpower. The crucial boy tenders a developed blurb. A top law clicks before a release. Why does our employee monitor the many lawyer? An ear fumes.'), (2, 'Misty in the Wings', 'When will a competing helmet react in a noise? A paragraph acts above the agenda! A kept delight repairs a controlling crush. Can the procedure vanish? The documented rectangle inconveniences a hysterical luggage. The learned tobacco screams.'), (3, 'Lord of the Minks', 'The undone complaint collapses past an east estate. The insulting nurse flames the era. A willed hierarchy surfaces. A tentative wife bites the consenting fence.'), (4, 'Ice in the Scent', 'A futile pump bangs against the cider. A night stomachs a wizard. How does the mania originate? Can a reject wreck a taking battle?'); ALTER TABLE `posts` ADD PRIMARY KEY (`post_id`); ALTER TABLE `posts` MODIFY `post_id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=5; COMMIT;
Field | Description |
post_id | The post ID and primary key. |
post_title | The post title. |
post_txt | The contents of the post. |
서버 측 스크립트
다음으로 모든 백엔드 프로세스를 처리하는 서버 측 스크립트를 작성합니다.
구성 파일
// MUTE NOTICES error_reporting(E_ALL & ~E_NOTICE); // DATABASE SETTINGS - CHANGE THESE TO YOUR OWN define('DB_HOST', 'localhost'); define('DB_NAME', 'test'); define('DB_CHARSET', 'utf8'); define('DB_USER', 'root'); define('DB_PASSWORD', ''); // AUTO FILE PATH define('PATH_LIB', __DIR__ . DIRECTORY_SEPARATOR);
우리가 만들어야 하는 첫 번째 서버 측 스크립트는 모든 설정과 내용을 저장하는 구성 파일입니다. 데이터베이스 설정을 원하는 대로 변경하십시오.
태그 라이브러리
class Tag { /* [DATABASE HELPER FUNCTIONS] */ protected $pdo = null; protected $stmt = null; public $lastID = null; function __construct () { // __construct() : connect to the database // PARAM : DB_HOST, DB_CHARSET, DB_NAME, DB_USER, DB_PASSWORD // ATTEMPT CONNECT try { $str = "mysql:host=" . DB_HOST . ";charset=" . DB_CHARSET; if (defined('DB_NAME')) { $str .= ";dbname=" . DB_NAME; } $this->pdo = new PDO( $str, DB_USER, DB_PASSWORD, [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, PDO::ATTR_EMULATE_PREPARES => false ] ); } // ERROR - CRITICAL STOP - THROW ERROR MESSAGE catch (Exception $ex) { print_r($ex); die(); } } function __destruct () { // __destruct() : close connection when done if ($this->stmt !== null) { $this->stmt = null; } if ($this->pdo !== null) { $this->pdo = null; } } function exec ($sql, $data=null) { // exec() : run insert, replace, update, delete query // PARAM $sql : SQL query // $data : array of data try { $this->stmt = $this->pdo->prepare($sql); $this->stmt->execute($data); $this->lastID = $this->pdo->lastInsertId(); } catch (Exception $ex) { $this->error = $ex; return false; } $this->stmt = null; return true; } function start () { // start() : auto-commit off $this->pdo->beginTransaction(); } function end ($commit=1) { // end() : commit or roll back? if ($commit) { $this->pdo->commit(); } else { $this->pdo->rollBack(); } } function fetchAll ($sql, $cond=null, $key=null, $value=null) { // fetchAll() : perform select query (multiple rows expected) // PARAM $sql : SQL query // $cond : array of conditions // $key : sort in this $key=>data order, optional // $value : $key must be provided. If string provided, sort in $key=>$value order. If function provided, will be a custom sort. $result = []; try { $this->stmt = $this->pdo->prepare($sql); $this->stmt->execute($cond); // Sort in given order if (isset($key)) { if (isset($value)) { if (is_callable($value)) { while ($row = $this->stmt->fetch(PDO::FETCH_NAMED)) { $result[$row[$key]] = $value($row); } } else { while ($row = $this->stmt->fetch(PDO::FETCH_NAMED)) { $result[$row[$key]] = $row[$value]; } } } else { while ($row = $this->stmt->fetch(PDO::FETCH_NAMED)) { $result[$row[$key]] = $row; } } } // No key-value sort order else { $result = $this->stmt->fetchAll(); } } catch (Exception $ex) { $this->error = $ex; return false; } // Return result $this->stmt = null; return count($result)==0 ? false : $result ; } function fetchCol ($sql, $cond=null) { // fetchCol() : yet another version of fetch that returns a flat array // I.E. Good for one column SELECT `col` FROM `table` $this->stmt = $this->pdo->prepare($sql); $this->stmt->execute($cond); $result = $this->stmt->fetchAll(PDO::FETCH_COLUMN, 0); return count($result)==0 ? false : $result; } /* [TAG FUNCTIONS] */ function getAll($id) { // get all tags for the given post ID $sql = "SELECT * FROM `tags` WHERE `post_id`=?"; return $this->fetchCol("SELECT `tag` FROM `tags` WHERE `post_id`=?", [$id]); } function search($tag) { // search() : search for posts with the given tag return $this->fetchAll( "SELECT p.* FROM `tags` t LEFT JOIN posts `p` USING (`post_id`) WHERE t.`tag`=?", [$tag], "post_id" ); } function reTag($id, $tags=null) { // reTag() : replace tags for the given post ID // PARAM $id : post ID // $tags : array of tags // Auto-commit off $this->start(); // Remove old tags first $pass = $this->exec( "DELETE FROM `tags` WHERE `post_id`=?", [$id] ); // Add new tags - If any // Might be a good idea to limit the total number of tags... if ($pass && is_array($tags) && count($tags)>0) { $sql = "INSERT INTO `tags` (`post_id`, `tag`) VALUES "; $data = []; foreach ($tags as $t) { $sql .= "(?,?),"; $data[] = $id; $data[] = $t; } $sql = substr($sql, 0, -1); $pass = $this->exec($sql, $data); } // End - commit or rollback $this->end($pass); return $pass; } }
도움! 이것은 영구적 인 머리 손상 (PHD)을 일으킬 수 있는 것처럼 보이지만 침착하게 조심스럽게 보십시오. 이 라이브러리는 두 섹션으로 나뉩니다.
Function | Description |
__construct | The constructor, will automatically connect to the database when the object is created. |
__destruct | The destructor, will automatically close the database connection when the object is destroyed. |
exec | Runs an insert, replace, update, or delete query. |
start | Auto-commit off, used for multiple queries and in conjunction with end. |
end | Commit or rollback? Used in conjunction with start. |
fetchAll | Run a select query, with multiple rows of results expected. |
fetchCol | Run a select query, but only on a single column of data. Will return a flat array of values on the selected column. |
Function | Description |
getAll | Get all the tags for the given post ID. |
search | Search for posts with specified tag. |
reTag | Delete and replace tags for the given post. |
AJAX HANDLER
// INIT require __DIR__ . DIRECTORY_SEPARATOR . "lib" . DIRECTORY_SEPARATOR . "2a-config.php"; require PATH_LIB . "2b-lib-tag.php"; $tagDB = new Tag(); // PROCESS AJAX REQUESTS switch ($_POST['req']) { // INVALID default: echo json_encode([ "status" => 0, "message" => "Invalid request" ]); break; // GET TAGS FOR POST case "get": $tags = $tagDB->getAll($_POST['post_id']); echo json_encode([ "status" => is_array($tags) ? 1 : 0, "message" => $tags ]); break; // SAVE TAGS case "save": $pass = $tagDB->reTag($_POST['post_id'], json_decode($_POST['tags'])); echo json_encode([ "status" => $pass ? 1 : 0, "message" => $pass ? "OK" : $tagDB->error ]); break; }
물론 라이브러리 자체는 자체적으로 아무것도 하지 않으므로 사용자 요청을 처리 할이 AJAX 핸들러를 작성해야 합니다. 작동 방식은 매우 간단합니다. 원하는 요청을 지정하기 위해 a $_POST['req']와 필요한 매개 변수를 차례로 지정합니다.
Request | Description |
get | Get all the tags for the given post ID. Parameters:
|
save | Save the tags for the given post ID. Parameters:
|
클라이언트 측 스크립트
퍼즐의 마지막 조각을 위해, 우리는 단지 사용자 인터페이스를 만들고 사용자가 게시물에 태그를 달도록 허용해야 합니다.
HTML
// INIT require __DIR__ . DIRECTORY_SEPARATOR . "lib" . DIRECTORY_SEPARATOR . "2a-config.php"; require PATH_LIB . "2b-lib-tag.php"; $tagDB = new Tag(); // GET TAGS $postID = 3; $tags = $tagDB->getAll($postID); // HTML <html> <head> <title>Simple Tag Demo</title> <script src="public/3b-tag.js"></script> <link href="public/3c-tag.css" rel="stylesheet"> </head> <body> <!-- [DOES NOT MATTER - YOUR POST] --> <h1> Lord of the Minks </h1> <p> The undone complaint collapses past an east estate. The insulting nurse flames the era. A willed hierarchy surfaces. A tentative wife bites the consenting fence. </p> <!-- [TAGS] --> <div id="tag_dock"> <h3>MANAGE TAGS</h3> <!-- [TAGS LIST] --> <div id="tag_list">if (is_array($tags)) { foreach ($tags as $t) { printf("<div class='tag'>%s</div>", $t); } } </div> <!-- [TAGS FORM] --> <!-- NOTE : CONTROLS DISABLED UNTIL PAGE FULLY LOADED --> <label for="tag_in"> Enter tags below, separate each with a comma.<br> Click on existing tags above to remove.<br> Remember to hit save to commit changes. </label> <input type="text" id="tag_in" maxlength="32" disabled/> <input type="hidden" id="post_id" value="<?=$postID?>"/> <input type="button" id="tag_save" value="Save" onclick="tag.save()" disabled/> </div> </body> </html>
이것은 단순한 더미 "편집 게시물"페이지이며, 유일한 중요한 부분은 아래의 태그 도켓이며 숨겨진 "post_id"필드를 참고하십시오.
자바 스크립트
var tag = { list : [], // Existing list of tags add : function (evt) { // tag.add() : press comma or enter to add tag if (evt.key=="," || evt.key=="Enter") { // Input check var tagged = evt.key=="," ? this.value.slice(0, -1) : this.value, error = ""; // Freaking joker empty input if (tagged=="") { error = "Please enter a valid tag"; } // Check if already in tags list if (error=="") { if (tag.list.indexOf(tagged) != -1) { error = tagged + " is already defined"; } } // OK - Create new tag if (error=="") { var newTag = document.createElement("div"); newTag.classList.add("tag"); newTag.innerHTML = tagged; newTag.addEventListener("click", tag.remove); document.getElementById("tag_list").appendChild(newTag); tag.list.push(tagged); this.value = ""; } // Not OK - Show error message else { this.value = tagged; alert(error); } } }, remove : function () { // tag.remove() : remove tag // Remove tag from list array first // var pos = tag.list.indexOf(this.innerHTML); tag.list.splice(tag.list.indexOf(this.innerHTML), 1); // Remove HTML tag document.getElementById("tag_list").removeChild(this); }, save : function () { // tag.save() : save the tags // DATA var data = new FormData(); data.append('req', 'save'); data.append('post_id', document.getElementById('post_id').value); data.append('tags', JSON.stringify(tag.list)); // AJAX var xhr = new XMLHttpRequest(); xhr.open('POST', "2c-ajax-tag.php", true); xhr.onload = function(){ var res = JSON.parse(this.response); // OK if (res.status==1) { alert("Save OK"); } else { alert(res.message); } }; xhr.send(data); return false; } }; // INIT ON WINDOW LOAD window.addEventListener("load", function() { // Get list of existing tags var all = document.querySelectorAll("#tag_list div.tag"); if (all.length>0) { for (var t of all) { tag.list.push(t.innerHTML); // Attach remove listener to tags t.addEventListener("click", tag.remove); } } // Attach comma listener to input field document.getElementById("tag_in").addEventListener("keyup", tag.add); // Enable controls document.getElementById("tag_in").disabled = false; document.getElementById("tag_save").disabled = false; });
마지막으로, 이것은 모든 마법을 수행 할 자바 스크립트입니다. 참고로 이것은 순수한 자바 스크립트입니다. jQuery도 없고 부트스트랩도 없습니다. 원하는 경우 직접 구현하거나 작동 방식을 변경하십시오.
Function | Description |
tag.add | This is the function that is attached to the |
tag.remove | Removes the given tag from the list. |
tag.save | Proceed with saving the tags list. |
CSS
/* [TAGS LIST] */ #tag_dock { max-width: 400px; padding: 20px; background: #f7f7f7; } #tag_dock h3 { margin: 0 0 3px 0; color: #bf4646; } #tag_list { width: 100%; display: flex; flex-direction: row; flex-wrap: wrap; } #tag_list div.tag { box-sizing: border-box; font-size: 0.9em; width: 30%; margin: 3px; padding: 5px; border: 1px solid #aaa; background: #e8f2ff; } #tag_list div:hover { background: #ffe8e8; cursor: pointer; } /* [TAGS FORM] */ #tag_dock label, #tag_dock input { box-sizing: border-box; display: block; width: 100%; margin-top: 8px; } #tag_dock label { font-size: 0.9em; color: #888; } #tag_dock input { padding: 8px; font-size: 1em; } #tag_dock input[type=button] { background: #2f75b7; color: #fff; cursor: pointer; border: 0; } /* [DOES NOT MATTER] */ html, body { font-family: arial, sans-serif; }
일부 화장품. 자신의 웹 사이트 테마에 맞게 자유롭게 변경하십시오.
유용한 비트
이것으로 코드가 완성되었으며 여기에 유용한 몇 가지 추가 기능이 있습니다.
구현하는 방법
초보자 코드 사용자 중 일부는 이것을 자신의 프로젝트에 구현하는 방법에 대해 혼란스러워해야합니다. 이 가이드의 3 단계를 기억하고 하나씩 해결하면 괜찮습니다.
등록된 댓글이 없습니다.