├── .env.example
├── .gitattributes
├── .gitignore
├── app
├── Console
│ ├── Commands
│ │ └── SendLatestMerchandiseNewsletterCommand.php
│ └── Kernel.php
├── Exceptions
│ └── Handler.php
├── Http
│ ├── Controllers
│ │ ├── Auth
│ │ │ ├── ForgotPasswordController.php
│ │ │ ├── LoginController.php
│ │ │ ├── RegisterController.php
│ │ │ └── ResetPasswordController.php
│ │ ├── Controller.php
│ │ ├── MerchandiseController.php
│ │ ├── TransactionController.php
│ │ └── UserAuthController.php
│ ├── Kernel.php
│ └── Middleware
│ │ ├── AuthUserAdminMiddleware.php
│ │ ├── AuthUserMiddleware.php
│ │ ├── DetectLanguageMiddleware.php
│ │ ├── EncryptCookies.php
│ │ ├── RedirectIfAuthenticated.php
│ │ ├── TrimStrings.php
│ │ ├── TrustProxies.php
│ │ └── VerifyCsrfToken.php
├── Jobs
│ ├── SendMerchandiseNewsletterJob.php
│ └── SendSignUpMailJob.php
├── Providers
│ ├── AppServiceProvider.php
│ ├── AuthServiceProvider.php
│ ├── BroadcastServiceProvider.php
│ ├── EventServiceProvider.php
│ └── RouteServiceProvider.php
├── Shop
│ └── Entity
│ │ ├── Merchandise.php
│ │ ├── Transaction.php
│ │ └── User.php
└── User.php
├── artisan
├── bootstrap
├── app.php
└── cache
│ └── .gitignore
├── composer.json
├── composer.lock
├── config
├── app.php
├── auth.php
├── broadcasting.php
├── cache.php
├── database.php
├── filesystems.php
├── mail.php
├── queue.php
├── services.php
├── session.php
└── view.php
├── database
├── .gitignore
├── factories
│ └── UserFactory.php
├── migrations
│ ├── 2014_10_12_000000_create_users_table.php
│ ├── 2017_08_20_061340_create_merchandise_table.php
│ ├── 2017_08_20_061534_create_transaction_table.php
│ ├── 2017_09_09_214403_add_facebook_id_to_users_table.php
│ └── 2018_07_08_000013_add_github_id_to_users_table.php
└── seeds
│ └── DatabaseSeeder.php
├── package.json
├── phpunit.xml
├── public
├── .htaccess
├── assets
│ ├── css
│ │ ├── bootstrap-theme.css
│ │ ├── bootstrap-theme.css.map
│ │ ├── bootstrap-theme.min.css
│ │ ├── bootstrap-theme.min.css.map
│ │ ├── bootstrap.css
│ │ ├── bootstrap.css.map
│ │ ├── bootstrap.min.css
│ │ ├── bootstrap.min.css.map
│ │ ├── font-awesome.css
│ │ ├── font-awesome.min.css
│ │ └── shop_laravel.css
│ ├── fonts
│ │ ├── FontAwesome.otf
│ │ ├── fontawesome-webfont.eot
│ │ ├── fontawesome-webfont.svg
│ │ ├── fontawesome-webfont.ttf
│ │ ├── fontawesome-webfont.woff
│ │ ├── fontawesome-webfont.woff2
│ │ ├── glyphicons-halflings-regular.eot
│ │ ├── glyphicons-halflings-regular.svg
│ │ ├── glyphicons-halflings-regular.ttf
│ │ ├── glyphicons-halflings-regular.woff
│ │ └── glyphicons-halflings-regular.woff2
│ ├── images
│ │ └── default-merchandise.png
│ └── js
│ │ ├── bootstrap.min.js
│ │ ├── jquery-2.2.4.min.js
│ │ ├── js.cookie.js
│ │ └── shop-laravel.js
├── css
│ └── app.css
├── favicon.ico
├── images
│ └── merchandise
│ │ └── .gitignore
├── index.php
├── robots.txt
└── web.config
├── readme.md
├── resources
├── assets
│ ├── images
│ │ ├── laravel-for-beginner-cn-hd.jpg
│ │ ├── laravel-for-beginner-cn.jpg
│ │ └── laravel-for-beginner.png
│ ├── js
│ │ ├── app.js
│ │ ├── bootstrap.js
│ │ └── components
│ │ │ └── Example.vue
│ └── sass
│ │ ├── _variables.scss
│ │ └── app.scss
├── lang
│ ├── en
│ │ ├── auth.php
│ │ ├── pagination.php
│ │ ├── passwords.php
│ │ ├── shop.php
│ │ └── validation.php
│ ├── zh-CN
│ │ ├── shop.php
│ │ └── validation.php
│ └── zh-TW
│ │ ├── shop.php
│ │ └── validation.php
└── views
│ ├── auth
│ ├── signIn.blade.php
│ └── signUp.blade.php
│ ├── components
│ └── validationErrorMessage.blade.php
│ ├── email
│ ├── merchandiseNewsletter.blade.php
│ └── signUpEmailNotification.blade.php
│ ├── errors
│ └── 403.blade.php
│ ├── layout
│ └── master.blade.php
│ ├── merchandise
│ ├── editMerchandise.blade.php
│ ├── listMerchandise.blade.php
│ ├── manageMerchandise.blade.php
│ └── showMerchandise.blade.php
│ ├── simple
│ └── auth
│ │ └── signUp.blade.php
│ ├── transaction
│ └── listUserTransaction.blade.php
│ └── welcome.blade.php
├── routes
├── api.php
├── channels.php
├── console.php
└── web.php
├── server.php
├── storage
├── app
│ ├── .gitignore
│ └── public
│ │ └── .gitignore
├── framework
│ ├── .gitignore
│ ├── cache
│ │ └── .gitignore
│ ├── sessions
│ │ └── .gitignore
│ ├── testing
│ │ └── .gitignore
│ └── views
│ │ └── .gitignore
└── logs
│ └── .gitignore
├── tests
├── CreatesApplication.php
├── Feature
│ └── ExampleTest.php
├── TestCase.php
└── Unit
│ └── ExampleTest.php
└── webpack.mix.js
/.env.example:
--------------------------------------------------------------------------------
1 | APP_NAME=Laravel
2 | APP_ENV=local
3 | APP_KEY=base64:vRgUKgnySoDPo+jaL5nelEMO2lQgsFSGDLXc99lxVuM=
4 | APP_DEBUG=true
5 | APP_LOG_LEVEL=debug
6 | APP_LOG=daily
7 | APP_URL=http://shop-laravel.local
8 |
9 | DB_CONNECTION=mysql
10 | DB_HOST=127.0.0.1
11 | DB_PORT=3306
12 | DB_DATABASE=homestead
13 | DB_USERNAME=homestead
14 | DB_PASSWORD=secret
15 |
16 | BROADCAST_DRIVER=log
17 | CACHE_DRIVER=file
18 | SESSION_DRIVER=file
19 | QUEUE_DRIVER=sync
20 |
21 | REDIS_HOST=127.0.0.1
22 | REDIS_PASSWORD=null
23 | REDIS_PORT=6379
24 |
25 | MAIL_DRIVER=smtp
26 | MAIL_HOST=smtp.mailtrap.io
27 | MAIL_PORT=2525
28 | MAIL_USERNAME=null
29 | MAIL_PASSWORD=null
30 | MAIL_ENCRYPTION=null
31 |
32 | PUSHER_APP_ID=
33 | PUSHER_APP_KEY=
34 | PUSHER_APP_SECRET=
35 |
36 |
37 | FB_CLIENT_ID=
38 | FB_CLIENT_SECRET=
39 | FB_REDIRECT=http://shop-laravel.local/user/auth/facebook-sign-in-callback
40 |
41 | GITHUB_CLIENT_ID=
42 | GITHUB_CLIENT_SECRET=
43 | GITHUB_REDIRECT=http://shop-laravel.local/user/auth/github-sign-in-callback
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | * text=auto
2 | *.css linguist-vendored
3 | *.scss linguist-vendored
4 | *.js linguist-vendored
5 | CHANGELOG.md export-ignore
6 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /node_modules
2 | /public/hot
3 | /public/storage
4 | /storage/*.key
5 | /vendor
6 | /.idea
7 | /.vagrant
8 | Homestead.json
9 | Homestead.yaml
10 | npm-debug.log
11 | yarn-error.log
12 | .env
13 | _ide_helper.php
--------------------------------------------------------------------------------
/app/Console/Commands/SendLatestMerchandiseNewsletterCommand.php:
--------------------------------------------------------------------------------
1 | info('寄送最新商品電子報(Start)');
47 | $this->info('撈取最新商品');
48 | // 撈取最新更新 10 筆可販售商品
49 | $total_row = 10;
50 | $MerchandiseCollection = Merchandise::OrderBy('created_at', 'desc')
51 | ->where('status', 'S') // 可販售
52 | ->take($total_row)
53 | ->get();
54 |
55 | // 寄送電子信給所有會員,每次撈取 1000 筆會員資料
56 | $row_per_page = 1000;
57 | $page = 1;
58 | while (true) {
59 | // 略過資料筆數
60 | $skip = ($page - 1) * $row_per_page;
61 | // 取得分頁會員資料
62 | $this->comment('取得使用者資料,第 ' . $page .' 頁,每頁 ' . $row_per_page . ' 筆');
63 | $UserCollection = User::orderBy('id', 'asc')
64 | ->skip($skip)
65 | ->take($row_per_page)
66 | ->get();
67 | if (!$UserCollection->count()) {
68 | // 沒有會員資料了,停止派送電子報
69 | $this->question('沒有使用者資料了,停止派送電子報');
70 | break;
71 | }
72 |
73 | // 派送會員電子信工作
74 | $this->comment('派送會員電子信(Start)');
75 | foreach ($UserCollection as $User) {
76 | SendMerchandiseNewsletterJob::dispatch($User, $MerchandiseCollection)
77 | ->onQueue('low');
78 | }
79 | $this->comment('派送會員電子信(End)');
80 |
81 | // 繼續找看看還有沒有需要寄送電子信的使用者
82 | $page++;
83 | }
84 |
85 | $this->info('寄送最新商品電子報(End)');
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/app/Console/Kernel.php:
--------------------------------------------------------------------------------
1 | command('shop:sendLatestMerchandiseNewsletter')
29 | ->fridays()
30 | ->dailyAt('18:00');
31 | }
32 |
33 | /**
34 | * Register the commands for the application.
35 | *
36 | * @return void
37 | */
38 | protected function commands()
39 | {
40 | $this->load(__DIR__.'/Commands');
41 |
42 | require base_path('routes/console.php');
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/app/Exceptions/Handler.php:
--------------------------------------------------------------------------------
1 | middleware('guest');
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/app/Http/Controllers/Auth/LoginController.php:
--------------------------------------------------------------------------------
1 | middleware('guest')->except('logout');
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/app/Http/Controllers/Auth/RegisterController.php:
--------------------------------------------------------------------------------
1 | middleware('guest');
40 | }
41 |
42 | /**
43 | * Get a validator for an incoming registration request.
44 | *
45 | * @param array $data
46 | * @return \Illuminate\Contracts\Validation\Validator
47 | */
48 | protected function validator(array $data)
49 | {
50 | return Validator::make($data, [
51 | 'name' => 'required|string|max:255',
52 | 'email' => 'required|string|email|max:255|unique:users',
53 | 'password' => 'required|string|min:6|confirmed',
54 | ]);
55 | }
56 |
57 | /**
58 | * Create a new user instance after a valid registration.
59 | *
60 | * @param array $data
61 | * @return \App\User
62 | */
63 | protected function create(array $data)
64 | {
65 | return User::create([
66 | 'name' => $data['name'],
67 | 'email' => $data['email'],
68 | 'password' => bcrypt($data['password']),
69 | ]);
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/app/Http/Controllers/Auth/ResetPasswordController.php:
--------------------------------------------------------------------------------
1 | middleware('guest');
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/app/Http/Controllers/Controller.php:
--------------------------------------------------------------------------------
1 | 'C', // 建立中
28 | 'name' => '', // 商品名稱
29 | 'name_en' => '', // 商品英文名稱
30 | 'introduction' => '', // 商品介紹
31 | 'introduction_en' => '', // 商品英文介紹
32 | 'photo' => null, // 商品照片
33 | 'price' => 0, // 價格
34 | 'remain_count' => 0, // 商品剩餘數量
35 | ];
36 | $Merchandise = Merchandise::create($merchandise_data);
37 |
38 | // 重新導向至商品編輯頁
39 | return redirect('/merchandise/' . $Merchandise->id . '/edit');
40 | }
41 |
42 | // 商品編輯頁
43 | public function merchandiseItemEditPage($merchandise_id)
44 | {
45 | // 撈取商品資料
46 | $Merchandise = Merchandise::findOrFail($merchandise_id);
47 |
48 | if (!is_null($Merchandise->photo)) {
49 | // 設定商品照片網址
50 | $Merchandise->photo = url($Merchandise->photo);
51 | }
52 |
53 | $binding = [
54 | 'title' => trans('shop.merchandise.edit'),
55 | 'Merchandise'=> $Merchandise,
56 | ];
57 | return view('merchandise.editMerchandise', $binding);
58 | }
59 |
60 | // 商品資料更新處理
61 | public function merchandiseItemUpdateProcess($merchandise_id)
62 | {
63 | // 撈取商品資料
64 | $Merchandise = Merchandise::findOrFail($merchandise_id);
65 | // 接收輸入資料
66 | $input = request()->all();
67 |
68 | // 驗證規則
69 | $rules = [
70 | // 商品狀態
71 | 'status'=> [
72 | 'required',
73 | 'in:C,S'
74 | ],
75 | // 商品名稱
76 | 'name' => [
77 | 'required',
78 | 'max:80',
79 | ],
80 | // 商品英文名稱
81 | 'name_en' => [
82 | 'required',
83 | 'max:80',
84 | ],
85 | // 商品介紹
86 | 'introduction' => [
87 | 'required',
88 | 'max:2000',
89 | ],
90 | // 商品英文介紹
91 | 'introduction_en' => [
92 | 'required',
93 | 'max:2000',
94 | ],
95 | // 商品照片
96 | 'photo'=>[
97 | 'file', // 必須為檔案
98 | 'image', // 必須為圖片
99 | 'max: 10240', // 10 MB
100 | ],
101 | // 商品價格
102 | 'price' => [
103 | 'required',
104 | 'integer',
105 | 'min:0',
106 | ],
107 | // 商品剩餘數量
108 | 'remain_count' => [
109 | 'required',
110 | 'integer',
111 | 'min:0',
112 | ],
113 | ];
114 |
115 | // 驗證資料
116 | $validator = Validator::make($input, $rules);
117 |
118 | if ($validator->fails()) {
119 | // 資料驗證錯誤
120 | return redirect('/merchandise/' . $Merchandise->id . '/edit')
121 | ->withErrors($validator)
122 | ->withInput();
123 | }
124 |
125 |
126 | if (isset($input['photo'])){
127 | // 有上傳圖片
128 | $photo = $input['photo'];
129 | // 檔案副檔名
130 | $file_extension = $photo->getClientOriginalExtension();
131 | // 產生自訂隨機檔案名稱
132 | $file_name = uniqid() . '.' . $file_extension;
133 | // 檔案相對路徑
134 | $file_relative_path = 'images/merchandise/' . $file_name;
135 | // 檔案存放目錄為對外公開 public 目錄下的相對位置
136 | $file_path = public_path($file_relative_path);
137 | // 裁切圖片
138 | $image = Image::make($photo)->fit(450, 300)->save($file_path);
139 | // 設定圖片檔案相對位置
140 | $input['photo'] = $file_relative_path;
141 | }
142 |
143 | // 商品資料更新
144 | $Merchandise->update($input);
145 |
146 | // 重新導向到商品編輯頁
147 | return redirect('/merchandise/' . $Merchandise->id . '/edit');
148 | }
149 |
150 | // 商品管理清單檢視
151 | public function merchandiseManageListPage()
152 | {
153 | // 每頁資料量
154 | $row_per_page = 10;
155 | // 撈取商品分頁資料
156 | $MerchandisePaginate = Merchandise::OrderBy('created_at', 'desc')
157 | ->paginate($row_per_page);
158 |
159 | // 設定商品圖片網址
160 | foreach ($MerchandisePaginate as &$Merchandise) {
161 | if (!is_null($Merchandise->photo)) {
162 | // 設定商品照片網址
163 | $Merchandise->photo = url($Merchandise->photo);
164 | }
165 | }
166 |
167 | $binding = [
168 | 'title' => trans('shop.merchandise.manage'),
169 | 'MerchandisePaginate'=> $MerchandisePaginate,
170 | ];
171 |
172 | return view('merchandise.manageMerchandise', $binding);
173 | }
174 |
175 | // 商品清單檢視
176 | public function merchandiseListPage()
177 | {
178 | // 每頁資料量
179 | $row_per_page = 10;
180 | // 撈取商品分頁資料
181 | $MerchandisePaginate = Merchandise::OrderBy('updated_at', 'desc')
182 | ->where('status', 'S') // 可販售
183 | ->paginate($row_per_page);
184 |
185 | // 設定商品圖片網址
186 | foreach ($MerchandisePaginate as &$Merchandise) {
187 | if (!is_null($Merchandise->photo)) {
188 | // 設定商品照片網址
189 | $Merchandise->photo = url($Merchandise->photo);
190 | }
191 | }
192 |
193 | $binding = [
194 | 'title' => trans('shop.merchandise.list'),
195 | 'MerchandisePaginate'=> $MerchandisePaginate,
196 | ];
197 |
198 | return view('merchandise.listMerchandise', $binding);
199 | }
200 |
201 | // 商品頁
202 | public function merchandiseItemPage($merchandise_id)
203 | {
204 | // 撈取商品資料
205 | $Merchandise = Merchandise::findOrFail($merchandise_id);
206 |
207 | if (!is_null($Merchandise->photo)) {
208 | // 設定商品照片網址
209 | $Merchandise->photo = url($Merchandise->photo);
210 | }
211 |
212 | $binding = [
213 | 'title' => trans('shop.merchandise.page'),
214 | 'Merchandise'=> $Merchandise,
215 | ];
216 | return view('merchandise.showMerchandise', $binding);
217 | }
218 |
219 | // 商品購買處理
220 | public function merchandiseItemBuyProcess($merchandise_id)
221 | {
222 | // 接收輸入資料
223 | $input = request()->all();
224 | // 驗證規則
225 | $rules = [
226 | // 商品購買數量
227 | 'buy_count' => [
228 | 'required',
229 | 'integer',
230 | 'min:1',
231 | ],
232 | ];
233 |
234 | // 驗證資料
235 | $validator = Validator::make($input, $rules);
236 |
237 | if ($validator->fails()) {
238 | // 資料驗證錯誤
239 | return redirect('/merchandise/' . $merchandise_id)
240 | ->withErrors($validator)
241 | ->withInput();
242 | }
243 |
244 | try {
245 | // 取得登入會員資料
246 | $user_id = session()->get('user_id');
247 | $User = User::findOrFail($user_id);
248 |
249 | // 交易開始
250 | DB::beginTransaction();
251 | // 取得商品資料
252 | $Merchandise = Merchandise::findOrFail($merchandise_id);
253 |
254 | // 購買數量
255 | $buy_count = $input['buy_count'];
256 | // 購買後剩餘數量
257 | $remain_count_after_buy = $Merchandise->remain_count - $buy_count;
258 | if ($remain_count_after_buy < 0) {
259 | // 購買後剩餘數量小於 0,不足以賣給使用者
260 | throw new Exception('商品數量不足,無法購買');
261 | }
262 | // 紀錄購買後剩餘數量
263 | $Merchandise->remain_count = $remain_count_after_buy;
264 | $Merchandise->save();
265 |
266 | // 總金額:總購買數量 * 商品價格
267 | $total_price = $buy_count * $Merchandise->price;
268 |
269 | $transaction_data = [
270 | 'user_id' => $User->id,
271 | 'merchandise_id' => $Merchandise->id,
272 | 'price' => $Merchandise->price,
273 | 'buy_count' => $buy_count,
274 | 'total_price' => $total_price,
275 | ];
276 |
277 | // 建立交易資料
278 | Transaction::create($transaction_data);
279 | // 交易結束
280 | DB::commit();
281 |
282 | // 回傳購物成功訊息
283 | $message = [
284 | 'msg' => [
285 | trans('shop.merchandise.purchase-success'),
286 | ],
287 | ];
288 | return redirect()
289 | ->to('/merchandise/' . $Merchandise->id)
290 | ->withErrors($message);
291 |
292 | } catch (Exception $exception) {
293 | // 恢復原先交易狀態
294 | DB::rollBack();
295 |
296 | // 回傳錯誤訊息
297 | $error_message = [
298 | 'msg' => [
299 | $exception->getMessage(),
300 | ],
301 | ];
302 | return redirect()
303 | ->back()
304 | ->withErrors($error_message)
305 | ->withInput();
306 | }
307 | }
308 | }
--------------------------------------------------------------------------------
/app/Http/Controllers/TransactionController.php:
--------------------------------------------------------------------------------
1 | get('user_id');
12 |
13 | // 每頁資料量
14 | $row_per_page = 10;
15 | // 撈取商品分頁資料
16 | $TransactionPaginate = Transaction::where('user_id', $user_id)
17 | ->OrderBy('created_at', 'desc')
18 | ->with('Merchandise')
19 | ->paginate($row_per_page);
20 |
21 | // 設定商品圖片網址
22 | foreach ($TransactionPaginate as &$Transaction) {
23 | if (!is_null($Transaction->Merchandise->photo)) {
24 | // 設定商品照片網址
25 | $Transaction->Merchandise->photo = url($Transaction->Merchandise->photo);
26 | }
27 | }
28 |
29 | $binding = [
30 | 'title' => trans('shop.transaction.list'),
31 | 'TransactionPaginate'=> $TransactionPaginate,
32 | ];
33 |
34 | return view('transaction.listUserTransaction', $binding);
35 | }
36 | }
--------------------------------------------------------------------------------
/app/Http/Controllers/UserAuthController.php:
--------------------------------------------------------------------------------
1 | trans('shop.auth.sign-up'),
20 | ];
21 | return view('auth.signUp', $binding);
22 | }
23 |
24 | // 處理註冊資料
25 | public function signUpProcess(){
26 | // 接收輸入資料
27 | $input = request()->all();
28 |
29 | // 驗證規則
30 | $rules = [
31 | // 暱稱
32 | 'nickname'=> [
33 | 'required',
34 | 'max:50',
35 | ],
36 | // Email
37 | 'email'=> [
38 | 'required',
39 | 'max:150',
40 | 'email',
41 | ],
42 | // 密碼
43 | 'password' => [
44 | 'required',
45 | 'same:password_confirmation',
46 | 'min:6',
47 | ],
48 | // 密碼驗證
49 | 'password_confirmation' => [
50 | 'required',
51 | 'min:6',
52 | ],
53 | // 帳號類型
54 | 'type' => [
55 | 'required',
56 | 'in:G,A'
57 | ],
58 | ];
59 |
60 | // 驗證資料
61 | $validator = Validator::make($input, $rules);
62 |
63 | if ($validator->fails()) {
64 | // 資料驗證錯誤
65 | return redirect('/user/auth/sign-up')
66 | ->withErrors($validator)
67 | ->withInput();
68 | }
69 |
70 | // 密碼加密
71 | $input['password'] = Hash::make($input['password']);
72 |
73 | // 新增會員資料
74 | $Users = User::create($input);
75 |
76 | // 寄送註冊通知信
77 | $mail_binding = [
78 | 'nickname' => $input['nickname'],
79 | 'email' => $input['email'],
80 | ];
81 |
82 | SendSignUpMailJob::dispatch($mail_binding)
83 | ->onQueue('high');
84 |
85 | // 重新導向到登入頁
86 | return redirect('/user/auth/sign-in');
87 | }
88 |
89 | // 登入
90 | public function signInPage(){
91 | $binding = [
92 | 'title' => trans('shop.auth.sign-in'),
93 | ];
94 | return view('auth.signIn', $binding);
95 | }
96 |
97 | // 處理登入資料
98 | public function signInProcess(){
99 | // 接收輸入資料
100 | $input = request()->all();
101 |
102 | // 驗證規則
103 | $rules = [
104 | // Email
105 | 'email'=> [
106 | 'required',
107 | 'max:150',
108 | 'email',
109 | ],
110 | // 密碼
111 | 'password' => [
112 | 'required',
113 | 'min:6',
114 | ],
115 | ];
116 |
117 | // 驗證資料
118 | $validator = Validator::make($input, $rules);
119 |
120 | if ($validator->fails()) {
121 | // 資料驗證錯誤
122 | return redirect('/user/auth/sign-in')
123 | ->withErrors($validator)
124 | ->withInput();
125 | }
126 |
127 | // 撈取使用者資料
128 | $User = User::where('email', $input['email'])->firstOrFail();
129 |
130 | // 檢查密碼是否正確
131 | $is_password_correct = Hash::check($input['password'], $User->password);
132 |
133 | if (!$is_password_correct) {
134 | // 密碼錯誤回傳錯誤訊息
135 | $error_message = [
136 | 'msg' => [
137 | '密碼驗證錯誤',
138 | ],
139 | ];
140 | return redirect('/user/auth/sign-in')
141 | ->withErrors($error_message)
142 | ->withInput();
143 | }
144 |
145 | // session 紀錄會員編號
146 | session()->put('user_id', $User->id);
147 |
148 | // 重新導向到原先使用者造訪頁面,沒有嘗試造訪頁則重新導向回首頁
149 | return redirect()->intended('/');
150 | }
151 |
152 |
153 |
154 | // 處理登出資料
155 | public function signOut(){
156 | // 清除 Session
157 | session()->forget('user_id');
158 |
159 | // 重新導向回首頁
160 | return redirect('/user/auth/sign-in');
161 | }
162 |
163 | // github 登入
164 | public function githubSignInProcess()
165 | {
166 | $redirect_url = env('GITHUB_REDIRECT');
167 |
168 | return Socialite::driver('github')
169 | ->redirectUrl($redirect_url)
170 | ->redirect();
171 | }
172 |
173 | // github 登入重新導向授權資料處理
174 | public function githubSignInCallbackProcess()
175 | {
176 | if (request()->error == 'access_denied') {
177 | throw new Exception('授權失敗,存取錯誤');
178 | }
179 |
180 | // 取得第三方使用者資料
181 | $GithubUser = Socialite::driver('github')->user();
182 |
183 | $github_email = $GithubUser->email;
184 |
185 | if (is_null($github_email)) {
186 | throw new Exception('未授權取得使用者 Email');
187 | }
188 | // 取得 Github 資料
189 | $github_id = $GithubUser->id;
190 | $github_name = $GithubUser->name;
191 |
192 | // 取得使用者資料是否有此 Github id 資料
193 | $User = User::where('github_id', $github_id)->first();
194 |
195 | if (is_null($User)) {
196 | // 沒有綁定 Github Id 的帳號,透過 Email 尋找是否有此帳號
197 | $User = User::where('email', $github_email)->first();
198 | if (!is_null($User)) {
199 | // 有此帳號,綁定 Github Id
200 | $User->github_id = $github_id;
201 | $User->save();
202 | }
203 | }
204 |
205 | if (is_null($User)){
206 | // 尚未註冊
207 | $input = [
208 | 'email' => $github_email, // Email
209 | 'nickname' => $github_name, // 暱稱
210 | 'password' => uniqid(), // 隨機產生密碼
211 | 'github_id' => $github_id, // Github ID
212 | 'type' => 'G', // 一般使用者
213 | ];
214 | // 密碼加密
215 | $input['password'] = Hash::make($input['password']);
216 | // 新增會員資料
217 | $User = User::create($input);
218 |
219 | // 寄送註冊通知信
220 | $mail_binding = [
221 | 'nickname' => $input['nickname'],
222 | 'email' => $input['email'],
223 | ];
224 |
225 | SendSignUpMailJob::dispatch($mail_binding)
226 | ->onQueue('high');
227 | }
228 |
229 | // 登入會員
230 | // session 紀錄會員編號
231 | session()->put('user_id', $User->id);
232 |
233 | // 重新導向到原先使用者造訪頁面,沒有嘗試造訪頁則重新導向回首頁
234 | return redirect()->intended('/');
235 | }
236 |
237 | // Facebook 登入
238 | public function facebookSignInProcess()
239 | {
240 | $redirect_url = env('FB_REDIRECT');
241 |
242 | return Socialite::driver('facebook')
243 | ->scopes(['user_friends'])
244 | ->redirectUrl($redirect_url)
245 | ->redirect();
246 | }
247 |
248 | // Facebook 登入重新導向授權資料處理
249 | public function facebookSignInCallbackProcess()
250 | {
251 | if (request()->error == 'access_denied') {
252 | throw new Exception('授權失敗,存取錯誤');
253 | }
254 | // 依照網域產出重新導向連結 (來驗證是否為發出時同一 callback )
255 | $redirect_url = env('FB_REDIRECT');
256 | // 取得第三方使用者資料
257 | $FacebookUser = Socialite::driver('facebook')
258 | ->fields([
259 | 'name',
260 | 'email',
261 | 'gender',
262 | 'verified',
263 | 'link',
264 | 'first_name',
265 | 'last_name',
266 | 'locale',
267 | ])
268 | ->redirectUrl($redirect_url)->user();
269 |
270 | $facebook_email = $FacebookUser->email;
271 |
272 | if (is_null($facebook_email)) {
273 | throw new Exception('未授權取得使用者 Email');
274 | }
275 | // 取得 Facebook 資料
276 | $facebook_id = $FacebookUser->id;
277 | $facebook_name = $FacebookUser->name;
278 |
279 | // 取得使用者資料是否有此 Facebook id 資料
280 | $User = User::where('facebook_id', $facebook_id)->first();
281 |
282 | if (is_null($User)) {
283 | // 沒有綁定 Facebook Id 的帳號,透過 Email 尋找是否有此帳號
284 | $User = User::where('email', $facebook_email)->first();
285 | if (!is_null($User)) {
286 | // 有此帳號,綁定 Facebook Id
287 | $User->facebook_id = $facebook_id;
288 | $User->save();
289 | }
290 | }
291 |
292 | if (is_null($User)){
293 | // 尚未註冊
294 | $input = [
295 | 'email' => $facebook_email, // Email
296 | 'nickname' => $facebook_name, // 暱稱
297 | 'password' => uniqid(), // 隨機產生密碼
298 | 'facebook_id' => $facebook_id, // Facebook ID
299 | 'type' => 'G', // 一般使用者
300 | ];
301 | // 密碼加密
302 | $input['password'] = Hash::make($input['password']);
303 | // 新增會員資料
304 | $User = User::create($input);
305 |
306 | // 寄送註冊通知信
307 | $mail_binding = [
308 | 'nickname' => $input['nickname'],
309 | 'email' => $input['email'],
310 | ];
311 |
312 | SendSignUpMailJob::dispatch($mail_binding)
313 | ->onQueue('high');
314 | }
315 |
316 | // 登入會員
317 | // session 紀錄會員編號
318 | session()->put('user_id', $User->id);
319 |
320 | // 重新導向到原先使用者造訪頁面,沒有嘗試造訪頁則重新導向回首頁
321 | return redirect()->intended('/');
322 | }
323 | }
--------------------------------------------------------------------------------
/app/Http/Kernel.php:
--------------------------------------------------------------------------------
1 | [
32 | // \App\Http\Middleware\EncryptCookies::class,
33 | \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
34 | \Illuminate\Session\Middleware\StartSession::class,
35 | // \Illuminate\Session\Middleware\AuthenticateSession::class,
36 | \Illuminate\View\Middleware\ShareErrorsFromSession::class,
37 | \App\Http\Middleware\VerifyCsrfToken::class,
38 | \Illuminate\Routing\Middleware\SubstituteBindings::class,
39 | // 偵測網站語言
40 | \App\Http\Middleware\DetectLanguageMiddleware::class,
41 | ],
42 |
43 | 'api' => [
44 | 'throttle:60,1',
45 | 'bindings',
46 | ],
47 | ];
48 |
49 | /**
50 | * The application's route middleware.
51 | *
52 | * These middleware may be assigned to groups or used individually.
53 | *
54 | * @var array
55 | */
56 | protected $routeMiddleware = [
57 | 'user.auth.admin'=> \App\Http\Middleware\AuthUserAdminMiddleware::class,
58 | 'user.auth'=> \App\Http\Middleware\AuthUserMiddleware::class,
59 | 'auth' => \Illuminate\Auth\Middleware\Authenticate::class,
60 | 'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
61 | 'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,
62 | 'can' => \Illuminate\Auth\Middleware\Authorize::class,
63 | 'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
64 | 'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
65 | ];
66 | }
67 |
--------------------------------------------------------------------------------
/app/Http/Middleware/AuthUserAdminMiddleware.php:
--------------------------------------------------------------------------------
1 | get('user_id');
24 |
25 | if (!is_null($user_id)) {
26 | // session 有會員編號,取得會員資料
27 | $User = User::findOrFail($user_id);
28 |
29 | if ($User->type == 'A') {
30 | // 是管理者,允許存取
31 | $is_allow_access = true;
32 | }
33 | }
34 |
35 | if (!$is_allow_access) {
36 | // 若不允許存取,重新導向至首頁
37 | return redirect()->to('/');
38 | }
39 |
40 | // 允許存取,繼續做下個請求的處理
41 | return $next($request);
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/app/Http/Middleware/AuthUserMiddleware.php:
--------------------------------------------------------------------------------
1 | get('user_id');
23 |
24 | if (!is_null($user_id)) {
25 | // session 有會員編號資料,允許存取
26 | $is_allow_access = true;
27 | }
28 |
29 | if (!$is_allow_access) {
30 | // 若不允許存取,重新導向至登入頁
31 | return redirect()->to('/user/auth/sign-in');
32 | }
33 |
34 | // 允許存取,繼續做下個請求的處理
35 | return $next($request);
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/app/Http/Middleware/DetectLanguageMiddleware.php:
--------------------------------------------------------------------------------
1 | cookie('shop_laravel_language');
21 |
22 | switch ($language) {
23 | // 語系指定為英文
24 | case 'en':
25 | app()->setLocale('en');
26 | break;
27 | // 語系指定為繁體中文
28 | case 'zh-CN':
29 | app()->setLocale('zh-CN');
30 | break;
31 | // 語系指定為繁體中文
32 | default:
33 | case 'zh-TW':
34 | app()->setLocale('zh-TW');
35 | break;
36 | }
37 |
38 | return $next($request);
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/app/Http/Middleware/EncryptCookies.php:
--------------------------------------------------------------------------------
1 | check()) {
21 | return redirect('/home');
22 | }
23 |
24 | return $next($request);
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/app/Http/Middleware/TrimStrings.php:
--------------------------------------------------------------------------------
1 | 'FORWARDED',
24 | Request::HEADER_X_FORWARDED_FOR => 'X_FORWARDED_FOR',
25 | Request::HEADER_X_FORWARDED_HOST => 'X_FORWARDED_HOST',
26 | Request::HEADER_X_FORWARDED_PORT => 'X_FORWARDED_PORT',
27 | Request::HEADER_X_FORWARDED_PROTO => 'X_FORWARDED_PROTO',
28 | ];
29 | }
30 |
--------------------------------------------------------------------------------
/app/Http/Middleware/VerifyCsrfToken.php:
--------------------------------------------------------------------------------
1 | User = $User;
29 | $this->MerchandiseCollection = $MerchandiseCollection;
30 |
31 | }
32 |
33 | /**
34 | * Execute the job.
35 | *
36 | * @return void
37 | */
38 | public function handle()
39 | {
40 | $mail_binding = [
41 | 'User' => $this->User,
42 | 'MerchandiseCollection' => $this->MerchandiseCollection,
43 | ];
44 |
45 | Mail::send(
46 | 'email.merchandiseNewsletter',
47 | $mail_binding,
48 | function($mail) use ($mail_binding)
49 | {
50 | $mail->to($mail_binding['User']->email);
51 | $mail->from('kejyun@gmail.com');
52 | $mail->subject('Shop Laravel 最新商品電子報');
53 | });
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/app/Jobs/SendSignUpMailJob.php:
--------------------------------------------------------------------------------
1 | mail_binding = $mail_binding;
25 | }
26 |
27 | /**
28 | * Execute the job.
29 | *
30 | * @return void
31 | */
32 | public function handle()
33 | {
34 | $mail_binding = $this->mail_binding;
35 |
36 | Mail::send(
37 | 'email.signUpEmailNotification',
38 | $mail_binding,
39 | function($mail) use ($mail_binding)
40 | {
41 | $mail->to($mail_binding['email']);
42 | $mail->from('kejyun@gmail.com');
43 | $mail->subject('恭喜註冊 Shop Laravel 成功');
44 | });
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/app/Providers/AppServiceProvider.php:
--------------------------------------------------------------------------------
1 | 'App\Policies\ModelPolicy',
17 | ];
18 |
19 | /**
20 | * Register any authentication / authorization services.
21 | *
22 | * @return void
23 | */
24 | public function boot()
25 | {
26 | $this->registerPolicies();
27 |
28 | //
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/app/Providers/BroadcastServiceProvider.php:
--------------------------------------------------------------------------------
1 | [
17 | 'App\Listeners\EventListener',
18 | ],
19 | ];
20 |
21 | /**
22 | * Register any events for your application.
23 | *
24 | * @return void
25 | */
26 | public function boot()
27 | {
28 | parent::boot();
29 |
30 | //
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/app/Providers/RouteServiceProvider.php:
--------------------------------------------------------------------------------
1 | mapApiRoutes();
39 |
40 | $this->mapWebRoutes();
41 |
42 | //
43 | }
44 |
45 | /**
46 | * Define the "web" routes for the application.
47 | *
48 | * These routes all receive session state, CSRF protection, etc.
49 | *
50 | * @return void
51 | */
52 | protected function mapWebRoutes()
53 | {
54 | Route::middleware('web')
55 | ->namespace($this->namespace)
56 | ->group(base_path('routes/web.php'));
57 | }
58 |
59 | /**
60 | * Define the "api" routes for the application.
61 | *
62 | * These routes are typically stateless.
63 | *
64 | * @return void
65 | */
66 | protected function mapApiRoutes()
67 | {
68 | Route::prefix('api')
69 | ->middleware('api')
70 | ->namespace($this->namespace)
71 | ->group(base_path('routes/api.php'));
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/app/Shop/Entity/Merchandise.php:
--------------------------------------------------------------------------------
1 | hasOne('App\Shop\Entity\Merchandise', 'id', 'merchandise_id');
27 | }
28 | }
--------------------------------------------------------------------------------
/app/Shop/Entity/User.php:
--------------------------------------------------------------------------------
1 | make(Illuminate\Contracts\Console\Kernel::class);
34 |
35 | $status = $kernel->handle(
36 | $input = new Symfony\Component\Console\Input\ArgvInput,
37 | new Symfony\Component\Console\Output\ConsoleOutput
38 | );
39 |
40 | /*
41 | |--------------------------------------------------------------------------
42 | | Shutdown The Application
43 | |--------------------------------------------------------------------------
44 | |
45 | | Once Artisan has finished running, we will fire off the shutdown events
46 | | so that any final work may be done by the application before we shut
47 | | down the process. This is the last thing to happen to the request.
48 | |
49 | */
50 |
51 | $kernel->terminate($input, $status);
52 |
53 | exit($status);
54 |
--------------------------------------------------------------------------------
/bootstrap/app.php:
--------------------------------------------------------------------------------
1 | singleton(
30 | Illuminate\Contracts\Http\Kernel::class,
31 | App\Http\Kernel::class
32 | );
33 |
34 | $app->singleton(
35 | Illuminate\Contracts\Console\Kernel::class,
36 | App\Console\Kernel::class
37 | );
38 |
39 | $app->singleton(
40 | Illuminate\Contracts\Debug\ExceptionHandler::class,
41 | App\Exceptions\Handler::class
42 | );
43 |
44 | /*
45 | |--------------------------------------------------------------------------
46 | | Return The Application
47 | |--------------------------------------------------------------------------
48 | |
49 | | This script returns the application instance. The instance is given to
50 | | the calling script so we can separate the building of the instances
51 | | from the actual running of the application and sending responses.
52 | |
53 | */
54 |
55 | return $app;
56 |
--------------------------------------------------------------------------------
/bootstrap/cache/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.gitignore
3 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "laravel/laravel",
3 | "description": "The Laravel Framework.",
4 | "keywords": ["framework", "laravel"],
5 | "license": "MIT",
6 | "type": "project",
7 | "require": {
8 | "php": ">=7.0.0",
9 | "barryvdh/laravel-ide-helper": "^2.4",
10 | "fideloper/proxy": "~3.3",
11 | "intervention/image": "^2.4",
12 | "laravel/framework": "5.5.*",
13 | "laravel/socialite": "^3.0",
14 | "laravel/tinker": "~1.0",
15 | "predis/predis": "^1.1"
16 | },
17 | "require-dev": {
18 | "filp/whoops": "~2.0",
19 | "fzaninotto/faker": "~1.4",
20 | "mockery/mockery": "0.9.*",
21 | "phpunit/phpunit": "~6.0"
22 | },
23 | "autoload": {
24 | "classmap": [
25 | "database/seeds",
26 | "database/factories"
27 | ],
28 | "psr-4": {
29 | "App\\": "app/"
30 | }
31 | },
32 | "autoload-dev": {
33 | "psr-4": {
34 | "Tests\\": "tests/"
35 | }
36 | },
37 | "extra": {
38 | "laravel": {
39 | "dont-discover": [
40 | ]
41 | }
42 | },
43 | "scripts": {
44 | "post-root-package-install": [
45 | "@php -r \"file_exists('.env') || copy('.env.example', '.env');\""
46 | ],
47 | "post-create-project-cmd": [
48 | "@php artisan key:generate"
49 | ],
50 | "post-autoload-dump": [
51 | "Illuminate\\Foundation\\ComposerScripts::postAutoloadDump",
52 | "@php artisan package:discover"
53 | ]
54 | },
55 | "config": {
56 | "preferred-install": "dist",
57 | "sort-packages": true,
58 | "optimize-autoloader": true
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/config/app.php:
--------------------------------------------------------------------------------
1 | env('APP_NAME', 'Laravel'),
18 |
19 | /*
20 | |--------------------------------------------------------------------------
21 | | Application Environment
22 | |--------------------------------------------------------------------------
23 | |
24 | | This value determines the "environment" your application is currently
25 | | running in. This may determine how you prefer to configure various
26 | | services your application utilizes. Set this in your ".env" file.
27 | |
28 | */
29 |
30 | 'env' => env('APP_ENV', 'production'),
31 |
32 | /*
33 | |--------------------------------------------------------------------------
34 | | Application Debug Mode
35 | |--------------------------------------------------------------------------
36 | |
37 | | When your application is in debug mode, detailed error messages with
38 | | stack traces will be shown on every error that occurs within your
39 | | application. If disabled, a simple generic error page is shown.
40 | |
41 | */
42 |
43 | 'debug' => env('APP_DEBUG', false),
44 |
45 | /*
46 | |--------------------------------------------------------------------------
47 | | Application URL
48 | |--------------------------------------------------------------------------
49 | |
50 | | This URL is used by the console to properly generate URLs when using
51 | | the Artisan command line tool. You should set this to the root of
52 | | your application so that it is used when running Artisan tasks.
53 | |
54 | */
55 |
56 | 'url' => env('APP_URL', 'http://localhost'),
57 |
58 | /*
59 | |--------------------------------------------------------------------------
60 | | Application Timezone
61 | |--------------------------------------------------------------------------
62 | |
63 | | Here you may specify the default timezone for your application, which
64 | | will be used by the PHP date and date-time functions. We have gone
65 | | ahead and set this to a sensible default for you out of the box.
66 | |
67 | */
68 |
69 | 'timezone' => 'Asia/Taipei',
70 | // 'timezone' => 'Asia/Shanghai',
71 |
72 | /*
73 | |--------------------------------------------------------------------------
74 | | Application Locale Configuration
75 | |--------------------------------------------------------------------------
76 | |
77 | | The application locale determines the default locale that will be used
78 | | by the translation service provider. You are free to set this value
79 | | to any of the locales which will be supported by the application.
80 | |
81 | */
82 |
83 | 'locale' => 'zh-TW',
84 | // 'locale' => 'zh-CN',
85 |
86 | /*
87 | |--------------------------------------------------------------------------
88 | | Application Fallback Locale
89 | |--------------------------------------------------------------------------
90 | |
91 | | The fallback locale determines the locale to use when the current one
92 | | is not available. You may change the value to correspond to any of
93 | | the language folders that are provided through your application.
94 | |
95 | */
96 |
97 | 'fallback_locale' => 'zh-TW',
98 |
99 | /*
100 | |--------------------------------------------------------------------------
101 | | Encryption Key
102 | |--------------------------------------------------------------------------
103 | |
104 | | This key is used by the Illuminate encrypter service and should be set
105 | | to a random, 32 character string, otherwise these encrypted strings
106 | | will not be safe. Please do this before deploying an application!
107 | |
108 | */
109 |
110 | 'key' => env('APP_KEY'),
111 |
112 | 'cipher' => 'AES-256-CBC',
113 |
114 | /*
115 | |--------------------------------------------------------------------------
116 | | Logging Configuration
117 | |--------------------------------------------------------------------------
118 | |
119 | | Here you may configure the log settings for your application. Out of
120 | | the box, Laravel uses the Monolog PHP logging library. This gives
121 | | you a variety of powerful log handlers / formatters to utilize.
122 | |
123 | | Available Settings: "single", "daily", "syslog", "errorlog"
124 | |
125 | */
126 |
127 | 'log' => env('APP_LOG', 'single'),
128 |
129 | 'log_level' => env('APP_LOG_LEVEL', 'debug'),
130 |
131 | /*
132 | |--------------------------------------------------------------------------
133 | | Autoloaded Service Providers
134 | |--------------------------------------------------------------------------
135 | |
136 | | The service providers listed here will be automatically loaded on the
137 | | request to your application. Feel free to add your own services to
138 | | this array to grant expanded functionality to your applications.
139 | |
140 | */
141 |
142 | 'providers' => [
143 |
144 | /*
145 | * Laravel Framework Service Providers...
146 | */
147 | Illuminate\Auth\AuthServiceProvider::class,
148 | Illuminate\Broadcasting\BroadcastServiceProvider::class,
149 | Illuminate\Bus\BusServiceProvider::class,
150 | Illuminate\Cache\CacheServiceProvider::class,
151 | Illuminate\Foundation\Providers\ConsoleSupportServiceProvider::class,
152 | Illuminate\Cookie\CookieServiceProvider::class,
153 | Illuminate\Database\DatabaseServiceProvider::class,
154 | Illuminate\Encryption\EncryptionServiceProvider::class,
155 | Illuminate\Filesystem\FilesystemServiceProvider::class,
156 | Illuminate\Foundation\Providers\FoundationServiceProvider::class,
157 | Illuminate\Hashing\HashServiceProvider::class,
158 | Illuminate\Mail\MailServiceProvider::class,
159 | Illuminate\Notifications\NotificationServiceProvider::class,
160 | Illuminate\Pagination\PaginationServiceProvider::class,
161 | Illuminate\Pipeline\PipelineServiceProvider::class,
162 | Illuminate\Queue\QueueServiceProvider::class,
163 | Illuminate\Redis\RedisServiceProvider::class,
164 | Illuminate\Auth\Passwords\PasswordResetServiceProvider::class,
165 | Illuminate\Session\SessionServiceProvider::class,
166 | Illuminate\Translation\TranslationServiceProvider::class,
167 | Illuminate\Validation\ValidationServiceProvider::class,
168 | Illuminate\View\ViewServiceProvider::class,
169 |
170 | /*
171 | * Package Service Providers...
172 | */
173 | // PhpStorm IDE Helper 開發完可刪,使用 php artisan ide-helper:generate
174 | // Barryvdh\LaravelIdeHelper\IdeHelperServiceProvider::class,
175 | /*
176 | * Application Service Providers...
177 | */
178 | App\Providers\AppServiceProvider::class,
179 | App\Providers\AuthServiceProvider::class,
180 | // App\Providers\BroadcastServiceProvider::class,
181 | App\Providers\EventServiceProvider::class,
182 | App\Providers\RouteServiceProvider::class,
183 |
184 | // 圖片處理
185 | Intervention\Image\ImageServiceProvider::class,
186 | // 社群登入
187 | Laravel\Socialite\SocialiteServiceProvider::class,
188 |
189 | ],
190 |
191 | /*
192 | |--------------------------------------------------------------------------
193 | | Class Aliases
194 | |--------------------------------------------------------------------------
195 | |
196 | | This array of class aliases will be registered when this application
197 | | is started. However, feel free to register as many as you wish as
198 | | the aliases are "lazy" loaded so they don't hinder performance.
199 | |
200 | */
201 |
202 | 'aliases' => [
203 | 'App' => Illuminate\Support\Facades\App::class,
204 | 'Artisan' => Illuminate\Support\Facades\Artisan::class,
205 | 'Auth' => Illuminate\Support\Facades\Auth::class,
206 | 'Blade' => Illuminate\Support\Facades\Blade::class,
207 | 'Broadcast' => Illuminate\Support\Facades\Broadcast::class,
208 | 'Bus' => Illuminate\Support\Facades\Bus::class,
209 | 'Cache' => Illuminate\Support\Facades\Cache::class,
210 | 'Config' => Illuminate\Support\Facades\Config::class,
211 | 'Cookie' => Illuminate\Support\Facades\Cookie::class,
212 | 'Crypt' => Illuminate\Support\Facades\Crypt::class,
213 | 'DB' => Illuminate\Support\Facades\DB::class,
214 | 'Eloquent' => Illuminate\Database\Eloquent\Model::class,
215 | 'Event' => Illuminate\Support\Facades\Event::class,
216 | 'File' => Illuminate\Support\Facades\File::class,
217 | 'Gate' => Illuminate\Support\Facades\Gate::class,
218 | 'Hash' => Illuminate\Support\Facades\Hash::class,
219 | 'Lang' => Illuminate\Support\Facades\Lang::class,
220 | 'Log' => Illuminate\Support\Facades\Log::class,
221 | 'Mail' => Illuminate\Support\Facades\Mail::class,
222 | 'Notification' => Illuminate\Support\Facades\Notification::class,
223 | 'Password' => Illuminate\Support\Facades\Password::class,
224 | 'Queue' => Illuminate\Support\Facades\Queue::class,
225 | 'Redirect' => Illuminate\Support\Facades\Redirect::class,
226 | 'Redis' => Illuminate\Support\Facades\Redis::class,
227 | 'Request' => Illuminate\Support\Facades\Request::class,
228 | 'Response' => Illuminate\Support\Facades\Response::class,
229 | 'Route' => Illuminate\Support\Facades\Route::class,
230 | 'Schema' => Illuminate\Support\Facades\Schema::class,
231 | 'Session' => Illuminate\Support\Facades\Session::class,
232 | 'Storage' => Illuminate\Support\Facades\Storage::class,
233 | 'URL' => Illuminate\Support\Facades\URL::class,
234 | 'Validator' => Illuminate\Support\Facades\Validator::class,
235 | 'View' => Illuminate\Support\Facades\View::class,
236 | // 圖片處理
237 | 'Image' => Intervention\Image\Facades\Image::class,
238 | // 社群登入
239 | 'Socialite' => Laravel\Socialite\Facades\Socialite::class,
240 | ],
241 |
242 | ];
243 |
--------------------------------------------------------------------------------
/config/auth.php:
--------------------------------------------------------------------------------
1 | [
17 | 'guard' => 'web',
18 | 'passwords' => 'users',
19 | ],
20 |
21 | /*
22 | |--------------------------------------------------------------------------
23 | | Authentication Guards
24 | |--------------------------------------------------------------------------
25 | |
26 | | Next, you may define every authentication guard for your application.
27 | | Of course, a great default configuration has been defined for you
28 | | here which uses session storage and the Eloquent user provider.
29 | |
30 | | All authentication drivers have a user provider. This defines how the
31 | | users are actually retrieved out of your database or other storage
32 | | mechanisms used by this application to persist your user's data.
33 | |
34 | | Supported: "session", "token"
35 | |
36 | */
37 |
38 | 'guards' => [
39 | 'web' => [
40 | 'driver' => 'session',
41 | 'provider' => 'users',
42 | ],
43 |
44 | 'api' => [
45 | 'driver' => 'token',
46 | 'provider' => 'users',
47 | ],
48 | ],
49 |
50 | /*
51 | |--------------------------------------------------------------------------
52 | | User Providers
53 | |--------------------------------------------------------------------------
54 | |
55 | | All authentication drivers have a user provider. This defines how the
56 | | users are actually retrieved out of your database or other storage
57 | | mechanisms used by this application to persist your user's data.
58 | |
59 | | If you have multiple user tables or models you may configure multiple
60 | | sources which represent each model / table. These sources may then
61 | | be assigned to any extra authentication guards you have defined.
62 | |
63 | | Supported: "database", "eloquent"
64 | |
65 | */
66 |
67 | 'providers' => [
68 | 'users' => [
69 | 'driver' => 'eloquent',
70 | 'model' => App\User::class,
71 | ],
72 |
73 | // 'users' => [
74 | // 'driver' => 'database',
75 | // 'table' => 'users',
76 | // ],
77 | ],
78 |
79 | /*
80 | |--------------------------------------------------------------------------
81 | | Resetting Passwords
82 | |--------------------------------------------------------------------------
83 | |
84 | | You may specify multiple password reset configurations if you have more
85 | | than one user table or model in the application and you want to have
86 | | separate password reset settings based on the specific user types.
87 | |
88 | | The expire time is the number of minutes that the reset token should be
89 | | considered valid. This security feature keeps tokens short-lived so
90 | | they have less time to be guessed. You may change this as needed.
91 | |
92 | */
93 |
94 | 'passwords' => [
95 | 'users' => [
96 | 'provider' => 'users',
97 | 'table' => 'password_resets',
98 | 'expire' => 60,
99 | ],
100 | ],
101 |
102 | ];
103 |
--------------------------------------------------------------------------------
/config/broadcasting.php:
--------------------------------------------------------------------------------
1 | env('BROADCAST_DRIVER', 'null'),
19 |
20 | /*
21 | |--------------------------------------------------------------------------
22 | | Broadcast Connections
23 | |--------------------------------------------------------------------------
24 | |
25 | | Here you may define all of the broadcast connections that will be used
26 | | to broadcast events to other systems or over websockets. Samples of
27 | | each available type of connection are provided inside this array.
28 | |
29 | */
30 |
31 | 'connections' => [
32 |
33 | 'pusher' => [
34 | 'driver' => 'pusher',
35 | 'key' => env('PUSHER_APP_KEY'),
36 | 'secret' => env('PUSHER_APP_SECRET'),
37 | 'app_id' => env('PUSHER_APP_ID'),
38 | 'options' => [
39 | //
40 | ],
41 | ],
42 |
43 | 'redis' => [
44 | 'driver' => 'redis',
45 | 'connection' => 'default',
46 | ],
47 |
48 | 'log' => [
49 | 'driver' => 'log',
50 | ],
51 |
52 | 'null' => [
53 | 'driver' => 'null',
54 | ],
55 |
56 | ],
57 |
58 | ];
59 |
--------------------------------------------------------------------------------
/config/cache.php:
--------------------------------------------------------------------------------
1 | env('CACHE_DRIVER', 'file'),
20 |
21 | /*
22 | |--------------------------------------------------------------------------
23 | | Cache Stores
24 | |--------------------------------------------------------------------------
25 | |
26 | | Here you may define all of the cache "stores" for your application as
27 | | well as their drivers. You may even define multiple stores for the
28 | | same cache driver to group types of items stored in your caches.
29 | |
30 | */
31 |
32 | 'stores' => [
33 |
34 | 'apc' => [
35 | 'driver' => 'apc',
36 | ],
37 |
38 | 'array' => [
39 | 'driver' => 'array',
40 | ],
41 |
42 | 'database' => [
43 | 'driver' => 'database',
44 | 'table' => 'cache',
45 | 'connection' => null,
46 | ],
47 |
48 | 'file' => [
49 | 'driver' => 'file',
50 | 'path' => storage_path('framework/cache/data'),
51 | ],
52 |
53 | 'memcached' => [
54 | 'driver' => 'memcached',
55 | 'persistent_id' => env('MEMCACHED_PERSISTENT_ID'),
56 | 'sasl' => [
57 | env('MEMCACHED_USERNAME'),
58 | env('MEMCACHED_PASSWORD'),
59 | ],
60 | 'options' => [
61 | // Memcached::OPT_CONNECT_TIMEOUT => 2000,
62 | ],
63 | 'servers' => [
64 | [
65 | 'host' => env('MEMCACHED_HOST', '127.0.0.1'),
66 | 'port' => env('MEMCACHED_PORT', 11211),
67 | 'weight' => 100,
68 | ],
69 | ],
70 | ],
71 |
72 | 'redis' => [
73 | 'driver' => 'redis',
74 | 'connection' => 'default',
75 | ],
76 |
77 | ],
78 |
79 | /*
80 | |--------------------------------------------------------------------------
81 | | Cache Key Prefix
82 | |--------------------------------------------------------------------------
83 | |
84 | | When utilizing a RAM based store such as APC or Memcached, there might
85 | | be other applications utilizing the same cache. So, we'll specify a
86 | | value to get prefixed to all our keys so we can avoid collisions.
87 | |
88 | */
89 |
90 | 'prefix' => 'laravel',
91 |
92 | ];
93 |
--------------------------------------------------------------------------------
/config/database.php:
--------------------------------------------------------------------------------
1 | env('DB_CONNECTION', 'mysql'),
17 |
18 | /*
19 | |--------------------------------------------------------------------------
20 | | Database Connections
21 | |--------------------------------------------------------------------------
22 | |
23 | | Here are each of the database connections setup for your application.
24 | | Of course, examples of configuring each database platform that is
25 | | supported by Laravel is shown below to make development simple.
26 | |
27 | |
28 | | All database work in Laravel is done through the PHP PDO facilities
29 | | so make sure you have the driver for your particular database of
30 | | choice installed on your machine before you begin development.
31 | |
32 | */
33 |
34 | 'connections' => [
35 |
36 | 'sqlite' => [
37 | 'driver' => 'sqlite',
38 | 'database' => env('DB_DATABASE', database_path('database.sqlite')),
39 | 'prefix' => '',
40 | ],
41 |
42 | 'mysql' => [
43 | 'driver' => 'mysql',
44 | 'host' => env('DB_HOST', '127.0.0.1'),
45 | 'port' => env('DB_PORT', '3306'),
46 | 'database' => env('DB_DATABASE', 'forge'),
47 | 'username' => env('DB_USERNAME', 'forge'),
48 | 'password' => env('DB_PASSWORD', ''),
49 | 'unix_socket' => env('DB_SOCKET', ''),
50 | 'charset' => 'utf8mb4',
51 | 'collation' => 'utf8mb4_unicode_ci',
52 | 'prefix' => '',
53 | 'strict' => true,
54 | 'engine' => null,
55 | ],
56 |
57 | 'pgsql' => [
58 | 'driver' => 'pgsql',
59 | 'host' => env('DB_HOST', '127.0.0.1'),
60 | 'port' => env('DB_PORT', '5432'),
61 | 'database' => env('DB_DATABASE', 'forge'),
62 | 'username' => env('DB_USERNAME', 'forge'),
63 | 'password' => env('DB_PASSWORD', ''),
64 | 'charset' => 'utf8',
65 | 'prefix' => '',
66 | 'schema' => 'public',
67 | 'sslmode' => 'prefer',
68 | ],
69 |
70 | 'sqlsrv' => [
71 | 'driver' => 'sqlsrv',
72 | 'host' => env('DB_HOST', 'localhost'),
73 | 'port' => env('DB_PORT', '1433'),
74 | 'database' => env('DB_DATABASE', 'forge'),
75 | 'username' => env('DB_USERNAME', 'forge'),
76 | 'password' => env('DB_PASSWORD', ''),
77 | 'charset' => 'utf8',
78 | 'prefix' => '',
79 | ],
80 |
81 | ],
82 |
83 | /*
84 | |--------------------------------------------------------------------------
85 | | Migration Repository Table
86 | |--------------------------------------------------------------------------
87 | |
88 | | This table keeps track of all the migrations that have already run for
89 | | your application. Using this information, we can determine which of
90 | | the migrations on disk haven't actually been run in the database.
91 | |
92 | */
93 |
94 | 'migrations' => 'migrations',
95 |
96 | /*
97 | |--------------------------------------------------------------------------
98 | | Redis Databases
99 | |--------------------------------------------------------------------------
100 | |
101 | | Redis is an open source, fast, and advanced key-value store that also
102 | | provides a richer set of commands than a typical key-value systems
103 | | such as APC or Memcached. Laravel makes it easy to dig right in.
104 | |
105 | */
106 |
107 | 'redis' => [
108 |
109 | 'client' => 'predis',
110 |
111 | 'default' => [
112 | 'host' => env('REDIS_HOST', '127.0.0.1'),
113 | 'password' => env('REDIS_PASSWORD', null),
114 | 'port' => env('REDIS_PORT', 6379),
115 | 'database' => 0,
116 | ],
117 |
118 | ],
119 |
120 | ];
121 |
--------------------------------------------------------------------------------
/config/filesystems.php:
--------------------------------------------------------------------------------
1 | env('FILESYSTEM_DRIVER', 'local'),
17 |
18 | /*
19 | |--------------------------------------------------------------------------
20 | | Default Cloud Filesystem Disk
21 | |--------------------------------------------------------------------------
22 | |
23 | | Many applications store files both locally and in the cloud. For this
24 | | reason, you may specify a default "cloud" driver here. This driver
25 | | will be bound as the Cloud disk implementation in the container.
26 | |
27 | */
28 |
29 | 'cloud' => env('FILESYSTEM_CLOUD', 's3'),
30 |
31 | /*
32 | |--------------------------------------------------------------------------
33 | | Filesystem Disks
34 | |--------------------------------------------------------------------------
35 | |
36 | | Here you may configure as many filesystem "disks" as you wish, and you
37 | | may even configure multiple disks of the same driver. Defaults have
38 | | been setup for each driver as an example of the required options.
39 | |
40 | | Supported Drivers: "local", "ftp", "s3", "rackspace"
41 | |
42 | */
43 |
44 | 'disks' => [
45 |
46 | 'local' => [
47 | 'driver' => 'local',
48 | 'root' => storage_path('app'),
49 | ],
50 |
51 | 'public' => [
52 | 'driver' => 'local',
53 | 'root' => storage_path('app/public'),
54 | 'url' => env('APP_URL').'/storage',
55 | 'visibility' => 'public',
56 | ],
57 |
58 | 's3' => [
59 | 'driver' => 's3',
60 | 'key' => env('AWS_KEY'),
61 | 'secret' => env('AWS_SECRET'),
62 | 'region' => env('AWS_REGION'),
63 | 'bucket' => env('AWS_BUCKET'),
64 | ],
65 |
66 | ],
67 |
68 | ];
69 |
--------------------------------------------------------------------------------
/config/mail.php:
--------------------------------------------------------------------------------
1 | env('MAIL_DRIVER', 'smtp'),
20 |
21 | /*
22 | |--------------------------------------------------------------------------
23 | | SMTP Host Address
24 | |--------------------------------------------------------------------------
25 | |
26 | | Here you may provide the host address of the SMTP server used by your
27 | | applications. A default option is provided that is compatible with
28 | | the Mailgun mail service which will provide reliable deliveries.
29 | |
30 | */
31 |
32 | 'host' => env('MAIL_HOST', 'smtp.mailgun.org'),
33 |
34 | /*
35 | |--------------------------------------------------------------------------
36 | | SMTP Host Port
37 | |--------------------------------------------------------------------------
38 | |
39 | | This is the SMTP port used by your application to deliver e-mails to
40 | | users of the application. Like the host we have set this value to
41 | | stay compatible with the Mailgun e-mail application by default.
42 | |
43 | */
44 |
45 | 'port' => env('MAIL_PORT', 587),
46 |
47 | /*
48 | |--------------------------------------------------------------------------
49 | | Global "From" Address
50 | |--------------------------------------------------------------------------
51 | |
52 | | You may wish for all e-mails sent by your application to be sent from
53 | | the same address. Here, you may specify a name and address that is
54 | | used globally for all e-mails that are sent by your application.
55 | |
56 | */
57 |
58 | 'from' => [
59 | 'address' => env('MAIL_FROM_ADDRESS', 'hello@example.com'),
60 | 'name' => env('MAIL_FROM_NAME', 'Example'),
61 | ],
62 |
63 | /*
64 | |--------------------------------------------------------------------------
65 | | E-Mail Encryption Protocol
66 | |--------------------------------------------------------------------------
67 | |
68 | | Here you may specify the encryption protocol that should be used when
69 | | the application send e-mail messages. A sensible default using the
70 | | transport layer security protocol should provide great security.
71 | |
72 | */
73 |
74 | 'encryption' => env('MAIL_ENCRYPTION', 'tls'),
75 |
76 | /*
77 | |--------------------------------------------------------------------------
78 | | SMTP Server Username
79 | |--------------------------------------------------------------------------
80 | |
81 | | If your SMTP server requires a username for authentication, you should
82 | | set it here. This will get used to authenticate with your server on
83 | | connection. You may also set the "password" value below this one.
84 | |
85 | */
86 |
87 | 'username' => env('MAIL_USERNAME'),
88 |
89 | 'password' => env('MAIL_PASSWORD'),
90 |
91 | /*
92 | |--------------------------------------------------------------------------
93 | | Sendmail System Path
94 | |--------------------------------------------------------------------------
95 | |
96 | | When using the "sendmail" driver to send e-mails, we will need to know
97 | | the path to where Sendmail lives on this server. A default path has
98 | | been provided here, which will work well on most of your systems.
99 | |
100 | */
101 |
102 | 'sendmail' => '/usr/sbin/sendmail -bs',
103 |
104 | /*
105 | |--------------------------------------------------------------------------
106 | | Markdown Mail Settings
107 | |--------------------------------------------------------------------------
108 | |
109 | | If you are using Markdown based email rendering, you may configure your
110 | | theme and component paths here, allowing you to customize the design
111 | | of the emails. Or, you may simply stick with the Laravel defaults!
112 | |
113 | */
114 |
115 | 'markdown' => [
116 | 'theme' => 'default',
117 |
118 | 'paths' => [
119 | resource_path('views/vendor/mail'),
120 | ],
121 | ],
122 |
123 | ];
124 |
--------------------------------------------------------------------------------
/config/queue.php:
--------------------------------------------------------------------------------
1 | env('QUEUE_DRIVER', 'sync'),
20 |
21 | /*
22 | |--------------------------------------------------------------------------
23 | | Queue Connections
24 | |--------------------------------------------------------------------------
25 | |
26 | | Here you may configure the connection information for each server that
27 | | is used by your application. A default configuration has been added
28 | | for each back-end shipped with Laravel. You are free to add more.
29 | |
30 | */
31 |
32 | 'connections' => [
33 |
34 | 'sync' => [
35 | 'driver' => 'sync',
36 | ],
37 |
38 | 'database' => [
39 | 'driver' => 'database',
40 | 'table' => 'jobs',
41 | 'queue' => 'default',
42 | 'retry_after' => 90,
43 | ],
44 |
45 | 'beanstalkd' => [
46 | 'driver' => 'beanstalkd',
47 | 'host' => 'localhost',
48 | 'queue' => 'default',
49 | 'retry_after' => 90,
50 | ],
51 |
52 | 'sqs' => [
53 | 'driver' => 'sqs',
54 | 'key' => 'your-public-key',
55 | 'secret' => 'your-secret-key',
56 | 'prefix' => 'https://sqs.us-east-1.amazonaws.com/your-account-id',
57 | 'queue' => 'your-queue-name',
58 | 'region' => 'us-east-1',
59 | ],
60 |
61 | 'redis' => [
62 | 'driver' => 'redis',
63 | 'connection' => 'default',
64 | 'queue' => 'default',
65 | 'retry_after' => 90,
66 | ],
67 |
68 | ],
69 |
70 | /*
71 | |--------------------------------------------------------------------------
72 | | Failed Queue Jobs
73 | |--------------------------------------------------------------------------
74 | |
75 | | These options configure the behavior of failed queue job logging so you
76 | | can control which database and table are used to store the jobs that
77 | | have failed. You may change them to any database / table you wish.
78 | |
79 | */
80 |
81 | 'failed' => [
82 | 'database' => env('DB_CONNECTION', 'mysql'),
83 | 'table' => 'failed_jobs',
84 | ],
85 |
86 | ];
87 |
--------------------------------------------------------------------------------
/config/services.php:
--------------------------------------------------------------------------------
1 | [
19 | 'domain' => env('MAILGUN_DOMAIN'),
20 | 'secret' => env('MAILGUN_SECRET'),
21 | ],
22 |
23 | 'ses' => [
24 | 'key' => env('SES_KEY'),
25 | 'secret' => env('SES_SECRET'),
26 | 'region' => 'us-east-1',
27 | ],
28 |
29 | 'sparkpost' => [
30 | 'secret' => env('SPARKPOST_SECRET'),
31 | ],
32 |
33 | 'stripe' => [
34 | 'model' => App\User::class,
35 | 'key' => env('STRIPE_KEY'),
36 | 'secret' => env('STRIPE_SECRET'),
37 | ],
38 |
39 | 'facebook' => [
40 | 'client_id' => env('FB_CLIENT_ID'),
41 | 'client_secret' => env('FB_CLIENT_SECRET'),
42 | 'redirect' => env('FB_REDIRECT'),
43 | ],
44 | 'github' => [
45 | 'client_id' => env('GITHUB_CLIENT_ID'),
46 | 'client_secret' => env('GITHUB_CLIENT_SECRET'),
47 | 'redirect' => env('GITHUB_REDIRECT'),
48 | ],
49 | ];
50 |
--------------------------------------------------------------------------------
/config/session.php:
--------------------------------------------------------------------------------
1 | env('SESSION_DRIVER', 'file'),
20 |
21 | /*
22 | |--------------------------------------------------------------------------
23 | | Session Lifetime
24 | |--------------------------------------------------------------------------
25 | |
26 | | Here you may specify the number of minutes that you wish the session
27 | | to be allowed to remain idle before it expires. If you want them
28 | | to immediately expire on the browser closing, set that option.
29 | |
30 | */
31 |
32 | 'lifetime' => 1440,
33 |
34 | 'expire_on_close' => false,
35 |
36 | /*
37 | |--------------------------------------------------------------------------
38 | | Session Encryption
39 | |--------------------------------------------------------------------------
40 | |
41 | | This option allows you to easily specify that all of your session data
42 | | should be encrypted before it is stored. All encryption will be run
43 | | automatically by Laravel and you can use the Session like normal.
44 | |
45 | */
46 |
47 | 'encrypt' => false,
48 |
49 | /*
50 | |--------------------------------------------------------------------------
51 | | Session File Location
52 | |--------------------------------------------------------------------------
53 | |
54 | | When using the native session driver, we need a location where session
55 | | files may be stored. A default has been set for you but a different
56 | | location may be specified. This is only needed for file sessions.
57 | |
58 | */
59 |
60 | 'files' => storage_path('framework/sessions'),
61 |
62 | /*
63 | |--------------------------------------------------------------------------
64 | | Session Database Connection
65 | |--------------------------------------------------------------------------
66 | |
67 | | When using the "database" or "redis" session drivers, you may specify a
68 | | connection that should be used to manage these sessions. This should
69 | | correspond to a connection in your database configuration options.
70 | |
71 | */
72 |
73 | 'connection' => null,
74 |
75 | /*
76 | |--------------------------------------------------------------------------
77 | | Session Database Table
78 | |--------------------------------------------------------------------------
79 | |
80 | | When using the "database" session driver, you may specify the table we
81 | | should use to manage the sessions. Of course, a sensible default is
82 | | provided for you; however, you are free to change this as needed.
83 | |
84 | */
85 |
86 | 'table' => 'sessions',
87 |
88 | /*
89 | |--------------------------------------------------------------------------
90 | | Session Cache Store
91 | |--------------------------------------------------------------------------
92 | |
93 | | When using the "apc" or "memcached" session drivers, you may specify a
94 | | cache store that should be used for these sessions. This value must
95 | | correspond with one of the application's configured cache stores.
96 | |
97 | */
98 |
99 | 'store' => null,
100 |
101 | /*
102 | |--------------------------------------------------------------------------
103 | | Session Sweeping Lottery
104 | |--------------------------------------------------------------------------
105 | |
106 | | Some session drivers must manually sweep their storage location to get
107 | | rid of old sessions from storage. Here are the chances that it will
108 | | happen on a given request. By default, the odds are 2 out of 100.
109 | |
110 | */
111 |
112 | 'lottery' => [2, 100],
113 |
114 | /*
115 | |--------------------------------------------------------------------------
116 | | Session Cookie Name
117 | |--------------------------------------------------------------------------
118 | |
119 | | Here you may change the name of the cookie used to identify a session
120 | | instance by ID. The name specified here will get used every time a
121 | | new session cookie is created by the framework for every driver.
122 | |
123 | */
124 |
125 | 'cookie' => env(
126 | 'SESSION_COOKIE',
127 | str_slug(env('APP_NAME', 'laravel'), '_').'_session'
128 | ),
129 |
130 | /*
131 | |--------------------------------------------------------------------------
132 | | Session Cookie Path
133 | |--------------------------------------------------------------------------
134 | |
135 | | The session cookie path determines the path for which the cookie will
136 | | be regarded as available. Typically, this will be the root path of
137 | | your application but you are free to change this when necessary.
138 | |
139 | */
140 |
141 | 'path' => '/',
142 |
143 | /*
144 | |--------------------------------------------------------------------------
145 | | Session Cookie Domain
146 | |--------------------------------------------------------------------------
147 | |
148 | | Here you may change the domain of the cookie used to identify a session
149 | | in your application. This will determine which domains the cookie is
150 | | available to in your application. A sensible default has been set.
151 | |
152 | */
153 |
154 | 'domain' => env('SESSION_DOMAIN', null),
155 |
156 | /*
157 | |--------------------------------------------------------------------------
158 | | HTTPS Only Cookies
159 | |--------------------------------------------------------------------------
160 | |
161 | | By setting this option to true, session cookies will only be sent back
162 | | to the server if the browser has a HTTPS connection. This will keep
163 | | the cookie from being sent to you if it can not be done securely.
164 | |
165 | */
166 |
167 | 'secure' => env('SESSION_SECURE_COOKIE', false),
168 |
169 | /*
170 | |--------------------------------------------------------------------------
171 | | HTTP Access Only
172 | |--------------------------------------------------------------------------
173 | |
174 | | Setting this value to true will prevent JavaScript from accessing the
175 | | value of the cookie and the cookie will only be accessible through
176 | | the HTTP protocol. You are free to modify this option if needed.
177 | |
178 | */
179 |
180 | 'http_only' => true,
181 |
182 | /*
183 | |--------------------------------------------------------------------------
184 | | Same-Site Cookies
185 | |--------------------------------------------------------------------------
186 | |
187 | | This option determines how your cookies behave when cross-site requests
188 | | take place, and can be used to mitigate CSRF attacks. By default, we
189 | | do not enable this as other CSRF protection services are in place.
190 | |
191 | | Supported: "lax", "strict"
192 | |
193 | */
194 |
195 | 'same_site' => null,
196 |
197 | ];
198 |
--------------------------------------------------------------------------------
/config/view.php:
--------------------------------------------------------------------------------
1 | [
17 | resource_path('views'),
18 | ],
19 |
20 | /*
21 | |--------------------------------------------------------------------------
22 | | Compiled View Path
23 | |--------------------------------------------------------------------------
24 | |
25 | | This option determines where all the compiled Blade templates will be
26 | | stored for your application. Typically, this is within the storage
27 | | directory. However, as usual, you are free to change this value.
28 | |
29 | */
30 |
31 | 'compiled' => realpath(storage_path('framework/views')),
32 |
33 | ];
34 |
--------------------------------------------------------------------------------
/database/.gitignore:
--------------------------------------------------------------------------------
1 | *.sqlite
2 |
--------------------------------------------------------------------------------
/database/factories/UserFactory.php:
--------------------------------------------------------------------------------
1 | define(App\User::class, function (Faker $faker) {
17 | static $password;
18 |
19 | return [
20 | 'name' => $faker->name,
21 | 'email' => $faker->unique()->safeEmail,
22 | 'password' => $password ?: $password = bcrypt('secret'),
23 | 'remember_token' => str_random(10),
24 | ];
25 | });
26 |
--------------------------------------------------------------------------------
/database/migrations/2014_10_12_000000_create_users_table.php:
--------------------------------------------------------------------------------
1 | increments('id');
20 | // Email
21 | $table->string('email', 150);
22 | // 密碼
23 | $table->string('password', 60);
24 | // 帳號類型(type):用於識別登入會員身份
25 | // - A(Admin): 管理者
26 | // - G(General): 一般會員
27 | $table->string('type', 1)->default('G'); // 帳號狀態
28 | // 暱稱
29 | $table->string('nickname', 50);
30 | // 時間戳記
31 | $table->timestamps();
32 |
33 | // 鍵值
34 | $table->unique(['email'], 'user_email_uk');
35 | });
36 | }
37 |
38 | /**
39 | * Reverse the migrations.
40 | *
41 | * @return void
42 | */
43 | public function down()
44 | {
45 | // 移除資料表
46 | Schema::dropIfExists('users');
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/database/migrations/2017_08_20_061340_create_merchandise_table.php:
--------------------------------------------------------------------------------
1 | increments('id');
20 | // 用於標記商品狀態,已上架的商品才能被消費者看到
21 | // - C(Create): 建立中
22 | // - S(Sell): 可販售
23 | $table->string('status', 1)->default('C');
24 | // 商品名稱
25 | $table->string('name', 80)->nullable();
26 | // 商品英文名稱
27 | $table->string('name_en', 80)->nullable();
28 | // 商品介紹
29 | $table->text('introduction');
30 | // 商品英文介紹
31 | $table->text('introduction_en');
32 | // 商品照片
33 | $table->string('photo', 50)->nullable();
34 | // 價格
35 | $table->integer('price')->default(0);
36 | // 商品剩餘數量
37 | $table->integer('remain_count')->default(0);
38 | // 時間戳記
39 | $table->timestamps();
40 |
41 | // 索引設定
42 | $table->index(['status'], 'merchandise_status_idx');
43 | });
44 | }
45 |
46 | /**
47 | * Reverse the migrations.
48 | *
49 | * @return void
50 | */
51 | public function down()
52 | {
53 | // 移除資料表
54 | Schema::dropIfExists('merchandise');
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/database/migrations/2017_08_20_061534_create_transaction_table.php:
--------------------------------------------------------------------------------
1 | increments('id');
20 | // 使用者編號
21 | $table->integer('user_id');
22 | // 商品編號
23 | $table->integer('merchandise_id');
24 | // 當時購買單價
25 | $table->integer('price');
26 | // 購買數量
27 | $table->integer('buy_count');
28 | // 交易總價格
29 | $table->integer('total_price');
30 | // 時間戳記
31 | $table->timestamps();
32 |
33 | // 索引設定
34 | $table->index(['user_id'], 'user_transaction_idx');
35 | });
36 | }
37 |
38 | /**
39 | * Reverse the migrations.
40 | *
41 | * @return void
42 | */
43 | public function down()
44 | {
45 | // 移除資料表
46 | Schema::dropIfExists('transaction');
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/database/migrations/2017_09_09_214403_add_facebook_id_to_users_table.php:
--------------------------------------------------------------------------------
1 | string('facebook_id', 30)
15 | ->nullable()
16 | ->after('password');
17 |
18 | // 建立索引
19 | $table->index(['facebook_id'], 'user_fb_idx');
20 | });
21 | }
22 |
23 | // 復原資料庫異動
24 | public function down()
25 | {
26 | Schema::table('users', function (Blueprint $table) {
27 | // 移除欄位
28 | $table->dropColumn('facebook_id');
29 | });
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/database/migrations/2018_07_08_000013_add_github_id_to_users_table.php:
--------------------------------------------------------------------------------
1 | string('github_id', 30)
15 | ->nullable()
16 | ->after('password');
17 |
18 | // 建立索引
19 | $table->index(['github_id'], 'user_github_idx');
20 | });
21 | }
22 |
23 | // 復原資料庫異動
24 | public function down()
25 | {
26 | Schema::table('users', function (Blueprint $table) {
27 | // 移除欄位
28 | $table->dropColumn('github_id');
29 | });
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/database/seeds/DatabaseSeeder.php:
--------------------------------------------------------------------------------
1 | call(UsersTableSeeder::class);
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "private": true,
3 | "scripts": {
4 | "dev": "npm run development",
5 | "development": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js",
6 | "watch": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --watch --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js",
7 | "watch-poll": "npm run watch -- --watch-poll",
8 | "hot": "cross-env NODE_ENV=development node_modules/webpack-dev-server/bin/webpack-dev-server.js --inline --hot --config=node_modules/laravel-mix/setup/webpack.config.js",
9 | "prod": "npm run production",
10 | "production": "cross-env NODE_ENV=production node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js"
11 | },
12 | "devDependencies": {
13 | "axios": "^0.16.2",
14 | "bootstrap-sass": "^3.3.7",
15 | "cross-env": "^5.0.1",
16 | "jquery": "^3.1.1",
17 | "laravel-mix": "^1.0",
18 | "lodash": "^4.17.4",
19 | "vue": "^2.1.10"
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/phpunit.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 | KeJyun 最新新書推薦
7 | |
8 | |
---|---|
11 | ![]() |
13 |
14 | Laravel 是 PHP 的框架(Framework),提供了很多開發網站或 API 所需的工具及環境,經過簡單的設定就可以完成資料的處理及顯示,使開發者可以很優雅且快速的開發出各個不同的產品。本書適合有 PHP 基礎的人,但不知道要怎麼選擇框架,或者不用框架的人也能夠明白它的好處。 15 |雖然 WordPress 也能夠架站,但如果有客製化需求,要開發各式各樣的網站,或提供 App 使用的 API,如此一來你只能選擇用框架,而 Laravel 是目前最受歡迎的。 16 |本書將解說為什麼要使用框架,以及理解框架的優缺點後,要怎麼選擇框架,並用框架快速建構一個網站。除非必要,否則書中會避免專業技術用語,盡量使用最生活化易懂的例子及語氣,讓大家更容易進入 Laravel 的世界。 17 |18 | 19 | 購書連結 20 |21 |
|
105 |
108 | ![]() |
110 |
111 | 112 | 113 | 購書連結 114 |115 |
|
175 |
名稱 | 7 |價格 | 8 |
---|---|
12 | 13 | {{ $Merchandise->name }} 14 | 15 | | 16 |17 | {{ $Merchandise->price }} 18 | | 19 |
{{ trans('shop.merchandise.fields.name') }} | 22 |{{ trans('shop.merchandise.fields.photo') }} | 23 |{{ trans('shop.merchandise.fields.price') }} | 24 |{{ trans('shop.merchandise.fields.remain-count') }} | 25 |
---|---|---|---|
29 | 30 | {{ $Merchandise->name }} 31 | 32 | | 33 |
34 |
35 | ![]() |
38 | {{ $Merchandise->price }} | 39 |{{ $Merchandise->remain_count }} | 40 |
{{ trans('shop.merchandise.fields.id') }} | 22 |{{ trans('shop.merchandise.fields.name') }} | 23 |{{ trans('shop.merchandise.fields.photo') }} | 24 |{{ trans('shop.merchandise.fields.status-name') }} | 25 |{{ trans('shop.merchandise.fields.price') }} | 26 |{{ trans('shop.merchandise.fields.remain-count') }} | 27 |{{ trans('shop.merchandise.edit') }} | 28 |
---|---|---|---|---|---|---|
{{ $Merchandise->id }} | 32 |{{ $Merchandise->name }} | 33 |
34 | ![]() |
36 | 37 | @if($Merchandise->status == 'C') 38 | 39 | {{ trans('shop.merchandise.fields.status.create') }} 40 | 41 | @else 42 | 43 | {{ trans('shop.merchandise.fields.status.sell') }} 44 | 45 | @endif 46 | | 47 |{{ $Merchandise->price }} | 48 |{{ $Merchandise->remain_count }} | 49 |50 | 51 | 52 | 53 | | 54 |
{{ trans('shop.merchandise.fields.name') }} | 22 |{{ $Merchandise->name }} | 23 |
---|---|
{{ trans('shop.merchandise.fields.photo') }} | 26 |
27 | ![]() |
29 |
{{ trans('shop.merchandise.fields.price') }} | 32 |33 | {{ $Merchandise->price }} 34 | | 35 |
{{ trans('shop.merchandise.fields.remain-count') }} | 38 |39 | {{ $Merchandise->remain_count }} 40 | | 41 |
{{ trans('shop.merchandise.fields.introduction') }} | 44 |45 | {{ $Merchandise->introduction }} 46 | | 47 |
50 | 64 | | 65 |
商品名稱 | 22 |圖片 | 23 |單價 | 24 |數量 | 25 |總金額 | 26 |購買時間 | 27 |
---|---|---|---|---|---|
31 | 32 | {{ $Transaction->Merchandise->name }} 33 | 34 | | 35 |
36 |
37 | ![]() |
40 | {{ $Transaction->price }} | 41 |{{ $Transaction->buy_count }} | 42 |{{ $Transaction->total_price }} | 43 |{{ $Transaction->created_at }} | 44 |