# Angular+PHP+MariaDB ## [先參照前篇安裝Angular](https://hackmd.io/@109213067/BJBlg0Mio/https%3A%2F%2Fhackmd.io%2FW3lwX8_rSPixiiLQ3U0AVg%3Fview) ## 流程 Angular -> 呼叫data.service.ts -> 呼叫PHP -> 操作MariaDB -> PHP回傳data.service.ts(如果有) -> Angular ## 1. <a href="https://www.digitalocean.com/community/tutorials/how-to-install-mariadb-on-rocky-linux-9">安裝MariaDB</a> * 登入mariadb ``` $ mysql -u username -p ``` * 使用資料庫test ```sql=1 use test; ``` * 新增資料表job ```sql=1 CREATE TABLE `job` (`id` int(10) NOT NULL PRIMARY KEY auto_increment,`title` varchar(10) NOT NULL,`date` varchar(10) NOT NULL,`content` varchar(50) NOT NULL,`done` varchar(1) NOT NULL) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; ``` ## 2. 安裝Apache ``` $ sudo dnf install httpd $ sudo systemctl start httpd $ sudo systemctl enable httpd ``` ## 3. 安裝PHP ``` $ sudo yum install php-{common,gmp,fpm,curl,intl,pdo,mbstring,gd,xml,cli,zip,mysqli} $ sudo yum module list php $ sudo yum module enable php:8.1 -y $ sudo vi /etc/httpd/conf/httpd.conf 在# LoadModule foo_module modules/mod_foo.so這行下面新增: AddHandler php-script .php $ sudo systemctl restart httpd $ sudo systemctl restart php-fpm ``` ## 4. PHP程式 * cd 到/var/www/html * 新增4個php檔 ``` $ sudo touch data.php $ sudo touch insert.php $ sudo touch edit.php $ sudo touch delete.php ``` * 4個檔案內容分別如下: * data.php: ``` php=1 <?php header('Access-Control-Allow-Origin: *'); header('Content-Type: application/json; charset=UTF-8'); header('Access-Control-Allow-Methods: GET,POST,PUT,DELETE,OPTIONS'); header('Access-Control-Max-Age: 3600'); header('Access-Control-Allow-Headers: Content-Type,Access-Control-Allow-Headers, Authorization, X-Requested-With'); header('Cache-Control: no-cache, must-revalidate'); header('Expires: Sat, 26 Jul 1997 05:00:00 GMT'); header('Access-Control-Allow-Credentials: true'); $servername = "localhost"; $username = "kenny"; $password = "Kenny061256"; $dbname = "test"; // Create connection $conn = new mysqli($servername, $username, $password, $dbname); // // Check connection if ($conn->connect_error) { die("Connection failed: " . $conn->connect_error); } $sql = "SELECT * FROM job"; $result = $conn->query($sql); $data = array(); if ($result->num_rows > 0) { // output data of each row while($row = $result->fetch_assoc()) { $data[] = $row; } } else { echo "0 results"; } echo json_encode($data); $conn->close(); ?> ``` * insert.php ``` php=1 <?php header('Access-Control-Allow-Origin: *'); header('Content-Type: application/json; charset=UTF-8'); header('Access-Control-Allow-Methods: GET,POST,PUT,DELETE,OPTIONS'); header('Access-Control-Max-Age: 3600'); header('Access-Control-Allow-Headers: Content-Type,Access-Control-Allow-Headers, Authorization, X-Requested-With'); header('Cache-Control: no-cache, must-revalidate'); header('Expires: Sat, 26 Jul 1997 05:00:00 GMT'); header('Access-Control-Allow-Credentials: true'); $servername = "localhost"; $username = "kenny"; $password = "Kenny061256"; $dbname = "test"; // Create connection $conn = new mysqli($servername, $username, $password, $dbname); // $data = json_decode(file_get_contents("php://input")); if (!isset($data->title) || !isset($data->date) || !isset($data->content)) { echo json_encode(['success' => 0, 'message' => 'some fields are empty!']); exit; }; // Check connection if ($conn->connect_error) { die("Connection failed: " . $conn->connect_error); } $title = $data->title; $date = $data->date; $content = $data->content; //$title = "123"; //$date = "111"; //$content = "333"; $sql = "insert into `job`(title,date,content,done)values("; $sql .= "'".$title."',"; $sql .= "'".$date."',"; $sql .= "'".$content."',"; $sql .= "'N')"; //$conn->execute($sql); $conn->query($sql); $conn->close(); ?> ``` * edit.php ```php=1 <?php header('Access-Control-Allow-Origin: *'); header('Content-Type: application/json; charset=UTF-8'); header('Access-Control-Allow-Methods: GET,POST,PUT,DELETE,OPTIONS'); header('Access-Control-Max-Age: 3600'); header('Access-Control-Allow-Headers: Content-Type,Access-Control-Allow-Headers, Authorization, X-Requested-With'); header('Cache-Control: no-cache, must-revalidate'); header('Expires: Sat, 26 Jul 1997 05:00:00 GMT'); header('Access-Control-Allow-Credentials: true'); $servername = "localhost"; $username = "kenny"; $password = "Kenny061256"; $dbname = "test"; // Create connection $conn = new mysqli($servername, $username, $password, $dbname); // $data = json_decode(file_get_contents("php://input")); if (!isset($data->title) || !isset($data->date) || !isset($data->content)) { echo json_encode(['success' => 0, 'message' => 'some fields are empty!']); exit; }; // Check connection if ($conn->connect_error) { die("Connection failed: " . $conn->connect_error); } $id = $data->id; $title = $data->title; $date = $data->date; $content = $data->content; //$id = "2"; //$title = "333"; //$date = "111"; //$content = "111"; $sql = "update `job` set title='"; $sql .= $title."',date='"; $sql .= $date."',content='"; $sql .= $content."' where id="; $sql .= $id; echo 123; //$conn->execute($sql); $conn->query($sql); $conn->close(); ?> ``` * delete.php ```php=1 <?php header('Access-Control-Allow-Origin: *'); header('Content-Type: application/json; charset=UTF-8'); header('Access-Control-Allow-Methods: GET,POST,PUT,DELETE,OPTIONS'); header('Access-Control-Max-Age: 3600'); header('Access-Control-Allow-Headers: Content-Type,Access-Control-Allow-Headers, Authorization, X-Requested-With'); header('Cache-Control: no-cache, must-revalidate'); header('Expires: Sat, 26 Jul 1997 05:00:00 GMT'); header('Access-Control-Allow-Credentials: true'); $servername = "localhost"; $username = "kenny"; $password = "Kenny061256"; $dbname = "test"; // Create connection $conn = new mysqli($servername, $username, $password, $dbname); // $data = json_decode(file_get_contents("php://input")); $id = $data->id; //$id = '1'; if (!isset($id)) { echo json_encode(['success' => 0, 'message' => 'id field is empty!']); exit; }; // Check connection if ($conn->connect_error) { die("Connection failed: " . $conn->connect_error); } $sql = "delete from `job` where id="; $sql.= $id; $conn->query($sql); $conn->close(); ?> ``` * 每個檔案都要加上檔頭(header),否則會有CORS錯誤 ## 5. 新增data.service.ts * data.service.ts會發送POST請求給php檔案,再把結果回傳給component.ts * 輸入以下指令新增data.service.ts ``` $ ng generate service data $ ng g s data(簡寫) ``` * data.service.ts的內容修改如下: ``` c#=1 import { HttpClient, HttpHeaders } from '@angular/common/http'; import { Injectable } from '@angular/core'; @Injectable() export class DataService { constructor(private http: HttpClient) {} getData() { const httpOptions = { headers: new HttpHeaders({ 'Content-Type': 'application/json', 'Authorization': 'Bearer ' + localStorage.getItem('token'), 'Access-Control-Alllow-Origin': '*', 'Access-Control-Allow-Methods': 'GET,POST,PUT,DELETE"' }) }; return this.http.post('http://localhost/data.php', httpOptions); } addData(job: Object){ return this.http.post('http://localhost/insert.php', job); } editData(job: Object){ return this.http.post('http://localhost/edit.php', job); } deleteData(job: Object){ return this.http.post('http://localhost/delete.php', job); } } ``` * 這裡定義4個可呼叫函式getData,addData,editData,deleteData,分別會呼叫4個php並回傳結果 ## 6. 修改module.ts * module.ts導入dataService,內容如下: ```c#=1 import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { AppRoutingModule } from './app-routing.module'; import { AppComponent } from './app.component'; import { EditJobComponent } from './edit-job/edit-job.component'; import { HttpClientModule } from '@angular/common/http'; import { DataService } from './data.service'; @NgModule({ declarations: [ AppComponent, EditJobComponent ], imports: [ BrowserModule, AppRoutingModule, HttpClientModule ], providers: [DataService], bootstrap: [AppComponent] }) export class AppModule { } ``` ## 7. 修改job.ts * 配合資料庫欄位加上id:string屬性,內容如下: ```c#=1 export interface job { id: string; title: string; date: string; content: string; done: boolean; } ``` ## 8. 修改app.component.ts和html * app.component.ts內容如下: ```c#=1 import { Component, OnInit} from '@angular/core'; import { job } from './job'; import { DataService } from './data.service'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) export class AppComponent implements OnInit{ // data:any; constructor(private dataService: DataService) { } ngOnInit() { this.dataService.getData().subscribe((data) => { this.data = data; }); } // title = 'firstapp'; // defined filter words search = ""; // defiend job //allJobs = [ //{title:"hello",date: new Date("2023-01-01"),content:"say hello",done:false}, //{title:"goodbye",date:new Date("2023-01-02"),content:"say goodbye",done:false}, //] // display job to html get myJob() { if (this.search=="" || this.search=="reset") { return this.data; //return this.allJobs; } let filter = this.search; const job = {keywords:filter}; // this.dataService.searchData(job).subscribe((data) => { // this.data = data; // }) let filterJobs = this.data.filter(function(data:job) { return (data.id === filter); }); return filterJobs; } // function addJob addJob(title: string, date:string, content: string) { if (title=="" || date=="Invalid Date" || content=="") { alert("please fill in all filed!"); return; } const job = {title:title,date:date,content:content}; this.dataService.addData(job).subscribe(response=>{ //console.log(response); alert('add job success!'); window.location.reload(); }); } // function removeJob removeJob(id: string) { const job = {id:id}; this.dataService.deleteData(job).subscribe(response=>{ alert('delete job success!'); window.location.reload(); }); } convertDate(date: string) { return new Date(date); } } ``` * app.component.html內容如下: ```html=1 <h1>Todo List</h1> <h2>Create Job</h2> <input #myTitle placeholder="job title"/> <input #myDate placeholder="job id"/> <input #myContent placeholder="job content"/> <button (click)="addJob(myTitle.value,myDate.value,myContent.value); myTitle.value='';myDate.value='';myContent.value=''">Create</button> <table> <tr><td>num</td><td>title</td><td>date</td><td>content</td><td>done</td></tr> <tr *ngFor="let i of myJob"><td>{{i.id}}</td><td>{{i.title}}</td><td>{{i.date}}</td><td>{{i.content}}</td><td>{{i.done}}</td><td><button (click)="removeJob(i.id)">Delete</button></td><app-edit-job [theJob]="i"></app-edit-job></tr> </table> <input #searcher placeholder="job id"/> <button (click)="search=searcher.value">search</button> <button (click)="search='reset';searcher.value=''">reset</button> ``` ## 9. 修改edit-job.component.ts和html * edit-job.components.ts內容如下: ```c#=1 import { Component, Input, OnInit} from '@angular/core'; import { job } from '../job'; import { DataService } from '../data.service'; @Component({ selector: 'app-edit-job', templateUrl: './edit-job.component.html', styleUrls: ['./edit-job.component.css'] }) export class EditJobComponent implements OnInit{ // data:any; // defined job which is Input from other file @Input() theJob!: job; constructor(private dataService: DataService) { } ngOnInit() { this.dataService.getData().subscribe((data) => { this.data = data; }); } // defined display display = false; id = ""; // edit the job editJob(title: string, date:string, content: string) { if (title=="" || date=="" || content=="") { alert("please fill in all filed!"); this.display=false; return; } this.id = this.theJob.id; const job = {id:this.id,title:title,date:date,content:content}; this.dataService.editData(job).subscribe(response=>{ //console.log(response); alert('edit job success!'); window.location.reload(); }); } convertDate(date: string) { return new Date(date); } } ``` * edit-job.component.html ```html=1 <div *ngIf="!display"> <button (click)="display=!display">Edit</button> </div> <div *ngIf="display"> <input #myTitle placeholder="job title"/> <input #myDate placeholder="job date"/> <input #myContent placeholder="job content"/> <button (click)="editJob(myTitle.value,myDate.value,myContent.value); myTitle.value='';myDate.value='';myContent.value=''">Edit</button> <button (click)="display=!display">Cancel</button> </div> ```