CodeIgniter CRUD

CodeIgniter 3.1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
CREATE TABLE news (
id int(11) NOT NULL AUTO_INCREMENT,
title varchar(128) NOT NULL,
slug varchar(128) NOT NULL,
text text NOT NULL,
create_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '新增貼文時間',
PRIMARY KEY(id),
KEY slug (slug)
)

CREATE TABLE posts (
id int NOT NULL AUTO_INCREMENT,
title varchar(255) NOT NULL,
slug varchar(255) NOT NULL,
body text NOT NULL,
create_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '新增貼文時間'
PRIMARY KEY(id)
)
1
2
3
4
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php/$1 [L]
準備
1
2
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css">
<script type="text/javascript" src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
  • 為什麼要用單一路口文件?
  • 建立controller和route
    • 讓url變得好看
    • 定義route規則
  • 建立model
    • slug把url去掉,只留下小寫的英文字母
    • 有點像是簡單的描述,例如:/車子/帥氣的法拉利
    • 可以用來當作唯一值用來識別某個資源(entry/resource)
    • 詳細說明可以看stackoverflow解釋(what-is-a-slug)
  • 和我想的比較不一樣的是,他把新聞系統的controller另外拆開
    • 本來想說寫在一起的
    • 分開也比較清楚
  • 建立列表頁和檢視頁面
  • 踩到的第一個坑是自己打錯字,找template的路徑
    • 不需要為繼承的父類別加上namespace
    • 改完route發現news不好使了
      • 先註解起來查原因
      • 檢視頁面的位置沒有改到view,從index那邊複製過來沒有修改到
    • 原來是沒有加htaccess的關係阿
      • 當發現怎麼改route都沒有用
      • 印出來看有設定,而且怎麼敲url就是不出來這時候就該設定htaccess了
    • 新增表單
      • 把檢視的route設定放到最後面
    • 刪除的坑(id)
      • 加上要刪除的編號之後,突然發現沒有辦法用open_form的方法了
      • 原先以為是因為寫法的關係造成的,結果是因為autoload沒有load到那個form的helper,殘念
      • 沒有對應到controller的method名稱
    • 編輯(slug)=>和view帶一樣的
      • bootstrap pull left把放在右邊的顯示到左邊
      • 要帶入view的slug進去,而不是用id
      • 少input hidden的id也想成功?
    • 新增navbar-right往右放
  • 小bug
    • 沒有取到URL參數的時候是取全部的文章
    • route的順序很重要,放錯了,url出不來,範圍比較小的放前面

踩坑特集

踩坑特集

  • 原本以為直接用bootstrap上面的jquery一定沒有問題,想不到ajax的時候出事了
  • 踩到自己的坑,剛好把洞洞填起來
    • 統一認action的post來決定要走哪一個表單
    • 沒有在最開始加上session_start就在那邊用session
    • 存在server的記憶體
  • JSON.parse回傳過來的值
  • require_once只有引入一次,結果需要引用多次(子留言)
    • mysql_timezone
      • 在mysql命令列中輸入,SET GLOBAL time_zone = ‘Asia/Taipei’;
    • SQL處理
      • real_escape_string($city); //PHP 7
  • 建立第一個Sample就踩坑
    • 用的是PHPUnit 7.4.3,貌似更新到PHPUnit 6之後的版本就要extends新的類別
    • 原本以為是路徑的問題,但聰明的phpunit會把tests資料夾下的所有檔案都跑過一次

Installing Ubuntu Laravel Environment

Prerequisite

  • If you want to get latest version of php, you need to update first.
  • Otherwise the lamp server will install older php version to your environment
1
2
3
sudo apt-add-repository ppa:ondrej/php
sudo apt-get update
sudo apt-get install php7.0

Usefull Command

  • sometime you need to check the installed packages in Ubuntu, you can use dpkg to list the packages status
1
dpkg --get-selections | grep php

Reference

Laravel PHP 7
ubuntu 14.04版本無法安裝my sql 5.6

unable to locate php7

laravel Ubuntu

Laravel Create Article

migrations

  • use increments to auto_increment id’s value
    • string type can not be null when applying to id
  • use timestamp to create two fields
    • created_at
    • updated_at
  • when using factory, the table will be automately filled update time and create date to the relative fields

Create Article

1
2
3
4
// create controller with resource methods
> php artisan make:controller ArticleController --resource
// create model along with migration
> php artisan make:model Article --migration

seeder

  • there are two ways to insert data to table via command line
1
2
> php artisan db:seed
> php artisan migrate:refresh --seed
  • both ways need adding customed seeder to Databaseseeder.php
    • db:seed however only execute seeds run() function
  • if you don’t want to use factory to get fake data, you can just use db:seed command to insert your customed data.
  • remember to add the seeder you create to Databaseseeder.php

set index to field(migrations)

  • belongsTo
1
2
3
4
 // \database\migrations\2018_10_05_094912_message_board_table.php

$table->unsignedInteger('user_id')->index();

1
2
3
4
// app\Messageboard.php
public function user() {
return $this->belongsTo(User::class);
}

Using Laravel AdminLTE

使用composer require引用套件

1
composer require jeroennoten/laravel-adminlte

配置config/app.php

  • 找尋使用的套件包
1
JeroenNoten\LaravelAdminLte\ServiceProvider::class,

執行publish命令

  • 將vendor產生的template複製一份到public資料夾
1
2
php artisan vendor:publish --provider="JeroenNoten\LaravelAdminLte\ServiceProvider" --tag=assets

AdminLTE

Laravel Intro

安裝完設定主目錄到documentRoot

資料夾

  • storage:編譯後產生的檔案、log檔案,設定為可以寫入的權限
  • bootstrap:框架啟動加載的檔案
  • cache:加載後產生的檔案
  • vendor:composer命令模組
  • app:系統核心代碼

開權限

  • chmod -R 777 storage
  • chmod -R 777 bootstrap/cache

Artisan工匠

  • symfony console元件為基礎架構
  • php artisan list
  • php artisan --version
  • php artisan make:command SendEmails
  • php artisan make:controller CustomerController

定義路由

  • 與客戶端互動
  • 用routes/web.php定義web相關的routes
  • 用routes/api.php定義api相關的routes

路由動詞

  • get/post/delete/put
  • 符合所有any
  • 符合一部分match
  • url helper透過url()轉向

Laravel Eloquent

繼承了Eloquent就相當於幹了很多事情

中間流(Builder)

  • 建立了一個對象,在中間不斷地去改變它
  • 用::訪問某個function,無論是否為static,__construct()都不會被調用
  • Builder對象不能直接存取Article對象,需要轉成終結對象,才能調用到裡面的屬性

模型關係

ORM

  • 一對一:不需要中間表
  • 多對多:用take優化性能

PHP的問題

  • 一個網頁一個PHP:使用漏洞攻擊(MVC)
  • 缺乏統一寫法:一個人離開要了解寫法(Framework)
  • 每次都從頭開始:開發效率低(不用重新造輪子)

Framework和Library差異

  • 由開發者決定是否要用方法

四類Framework

  • codeIgniter:支援最廣(適合接案使用)
  • laravel:全功能(學習門檻高,底層用symfony)
  • slim:簡約(restful API使用)
  • phalcon:快速(C語言開發)

Laravel環境難裝

  • 用最新的PHP新功能
  • 用罕見的Extension

指令很多

  • composer:安裝套件
  • artisan:cli tool

體驗高手如何寫出OOP

  • 把商業邏輯無關又常常用到的功能抽出來
  • 套件為主的開發方式,名稱衝突問題(NameSpace)
  • ORM:SQL物件化
  • Migration:欄位開錯,版本控管
  • TDD:先寫測試在寫開發

TDD好處

  • 對Spec更加了解
  • 不用擔心重構的問題
  • 提早發現架構的問題

參考

Laravel Command

Tools

Lang

  • Laravel Lang
  • composer require caouecs/laravel-lang:~3.0
  • second way to change language is to put json language file to lang folder

Services

  • Auth
    • attempt(): to login and register session data. Verify email and unencrypted password
    • logout()

Migration

1
2
3
4
* php artisan make:migration UserTestTable
* php artisan make:seeder UserTestSeeder
* php artisan make:model UserTestSeeder
* php artisan migrate:refresh --model=UserTestSeeder --seed

FORM CRUD

  • @csrf @method(‘DELETE’): filter request
  • csrf
  • php artisan make:policy PostPolicy: to avoid not authorize user to delete
  • using @can(‘delete’, $user) to toggle delete button
  • @csrf @method(‘PUT’): fake update method using put instead
  • Method Field

Helpers

Artisan Command

1
2
3
4
5
php artisan make:controller IndexController
php artisan make:controller UserController --resource
php artisan route:list
php artisan migrate
php artisan make:policy --model=User UserPolicy

Session Driver

  • change .env session_driver to session
    • laravel will create sessoin table to record user login message
    • once you change the driver type, you need to refresh all record to get the correct result
1
2
php artisan session:table
php artisan migrate:refresh --seed

Create App Key & Smtp Setting

smtp gmail setting

1
2
php artisan key:generate
php artisan make:mail RegMail

create factory data

1
2
3
// manually added records
php artisan tinker
factory(App\User::class, 20)->create();
1
2
3
4
5
6
// execute by db:seed
php artisan make:seeder UsersSeeder
// rewrite the DatabaseSeeder.php run method by using factory
// factory(App\User::class, 20)->create();
php artisan db:seed
php artisan migrate:refresh --seed

Using Policy

  • create policy
    • php artisan make:policy --model=user UserPolicy
  • AuthServiceProvider add Policy
    • ‘App\User’ => UserPolicy::class,
    • remember to add namespace before using this policy
  • authorize controller destroy method to execute delete method
    • $this->authorize(‘delete’, $user);

Notice

  • routes/web.php
  1. use get to access controller function
    • alias name for changing back to home page
  2. use resource to create default CRUD method
    • no need to create additional view blade files
  3. laravel 5.4 support emoji for MySQL 5.7.7
    • every time start the app
    • Providers\AppServiceProvider.php
    • config\app.php
1
2
Route::get('/', 'IndexController@home')->name('home');
Route::resource('user', 'UserController');
1
2
3
4
public function boot()
{
Schema::defaultStringLength(191);
}