Home 라라벨로 배우는 php 웹 프로그래밍
Post
Cancel

라라벨로 배우는 php 웹 프로그래밍

라라벨로 배우는 실전 PHP 웹 프로그래밍

PART 1 라라벨 입문

6. 데이터베이스와 모델

라라벨은 Mysql을 기본값으로 설정하지만, MariaDB, Postgres, SqlLite, SqlServer 등을 사용 가능하다.

옐로퀀트

데이트베이스의 레코드를 객체로 표현하는 객체 관계 모델의 구현체이며, PHP의 클래스 문법으로 RDB와 상호 작용이 가능 하다.

  • 자바의 jpa와 유사한 기능같다

6.1 데이터베이스 준비

이전에 헀던 root 비밀번호를 입력하여 접속한다

trouble shooting

Can’t connect to local MySQL server through socket ‘/tmp/mysql.sock’에러 발생시, mysql 서버가 작동중인지 확인해 보자

MySql 접속

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$ mysql -uroot -p

Enter password: 
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 13
Server version: 8.0.22 Homebrew

Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql>

데이터를 만든다

데이터베이스 만들기

1
2
3
4
5
6
7
8
9
10
11
12
13
14
mysql> create database myapp;
Query OK, 1 row affected (0.01 sec)

mysql> create user 'homestead' identified by 'secert';
Query OK, 0 rows affected (0.02 sec)

mysql> grant all privileges on myapp.* to 'homestead';
Query OK, 0 rows affected (0.01 sec)

mysql> flush privileges;
Query OK, 0 rows affected (0.00 sec)

mysql> quit
Bye

MySQL 8.0.4 이상부터 계정 인증 방식이 변경

1
mysql> ALTER USER 'homestead' IDENTIFIED WITH mysql_native_password BY 'secert';

생성한 새 계정(homestead)으로 로그인을 한다

MySql 접속

1
$ mysql -uhomestead -p

스키마와 테이블을 생성한다

스키마, 테이블 생성

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
mysql> use myapp;
Database changed
mysql> create table posts(
    -> id int(11) unsigned not null auto_increment primary key,
    -> title varchar(255),
    -> body text
    -> ) engine=innodb default charset=utf8 collate=utf8_unicode_ci;
Query OK, 0 rows affected, 3 warnings (0.01 sec)

mysql> describe posts;
+-------+--------------+------+-----+---------+----------------+
| Field | Type         | Null | Key | Default | Extra          |
+-------+--------------+------+-----+---------+----------------+
| id    | int unsigned | NO   | PRI | NULL    | auto_increment |
| title | varchar(255) | YES  |     | NULL    |                |
| body  | text         | YES  |     | NULL    |                |
+-------+--------------+------+-----+---------+----------------+
3 rows in set (0.01 sec)

6.2 REPL

REPL(Read-Evalutate-Print-Loop)은 코솔 환경에서 명령을 내리고 실행 결과를 확인 하기 위해 사용하는 도구

팅커(REPL) 콘솔

1
php artisan tinker

NOTE
라라벨 명령줄 인터페이스 아티즌

1
$ php artisan [실행할 명령] [명령인자] --[옵션]

6.3 데이터베이스 쿼리

데이터베이스 접속을 하기 위해 설정파일을 변경 필요

.env

1
2
3
4
5
6
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=myapp
DB_USERNAME=homestead
DB_PASSWORD=secert

QueryException

1
2
3
4
$ php artisan tinker
Psy Shell v0.10.5 (PHP 7.3.11  cli) by Justin Hileman
>>> db::select('select * from posts');
=> []

QueryInsert

1
2
3
4
>>> db::insert('insert into posts(title , body) values(?,?)',['Ola Database','tinker']);
=> true
>>> db::insert('insert into posts(title , body) values(?,?)',['Hello Database','tinker2']);
=> true

db는 라라벨의 특수 문법인 파사드(facade)문법이다. insert는 메서드 이름이다.

물음표는 PDO::prepare()의 인자를 바인딩하는 문법이다. 사용자 입력값 등을 깨끗하게 세탁한 후 SQL 문장에 바인딩함으로써, SQL 삽입과 같은 악의적인 공격을 원천적으로 차단하기 위해서이다.

파사드

파사드는 디자인 패턴의 일종으로 라라벨의 파사드는 디자인 패턴의 파사드가 아닌 라라벨 만의 문법이다.

컬렉션 쿼리

배열 형태를 갖는 컬렉션이 반환후, 값에 접근해 본다

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
>>>> $posts = db::select('select * from posts');
=> [
     {#3355
       +"id": 1,
       +"title": "Ola Database",
       +"body": "tinker",
     },
     {#3359
       +"id": 2,
       +"title": "Hello Database",
       +"body": "tinker2",
     },
   ]
>>> $posts[0] -> title;
=> "Ola Database"

컬렉션이 아닌 단일 데이터 인스턴스를 얻을수 있다.

인스턴스 쿼리

인덱스 시작은 0 부터가 아닌 1부터 시작한다

1
2
3
4
5
6
>>> $post = db::selectone('select * from posts where id = ?',[1]);
=> {#3366
     +"id": 1,
     +"title": "Ola Database",
     +"body": "tinker",
   }

6.4 쿼리빌더

SQL 문장을 PHP 클래스 문법을 사용한다
쿼리 빌더는 db::table(‘posts’)와 같이 무조건 table(string $table) 메서드로 시작해야 한다.

get() 메소드로 컬렉션 조회

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
>>> db::table('posts')->get();
=> Illuminate\Support\Collection {#3376
     all: [
       {#3371
         +"id": 1,
         +"title": "Ola Database",
         +"body": "tinker",
       },
       {#3377
         +"id": 2,
         +"title": "Hello Database",
         +"body": "tinker2",
       },
     ],
   }

first() , find() 메서드로 인스턴스 조회

1
2
3
4
5
6
7
8
9
10
11
12
>>> db::table('posts')->first();
=> {#3373
     +"id": 1,
     +"title": "Ola Database",
     +"body": "tinker",
   }
>>> db::table('posts')->find(1);
=> {#3369
     +"id": 1,
     +"title": "Ola Database",
     +"body": "tinker",
   }

원하는 컬럼만 조회 할때

1
2
3
4
5
6
7
8
>>> db::table('posts')->first('id');
=> {#3379
     +"id": 1,
   }
>>> db::table('posts')->select('id')->find(1);
=> {#3377
     +"id": 1,
   }
조건절은 where(stringarray Closure $column , string $operator = null, mixed $value = null) 메서드로 쿼리 조건을 정의할 수 있다.

조건절

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
>>> db::table('posts')->where('id','=',1)->get();
=> Illuminate\Support\Collection {#3391
     all: [
       {#3379
         +"id": 1,
         +"title": "Ola Database",
         +"body": "tinker",
       },
     ],
   }
>>> db::table('posts')->where('id',1)->get();
=> Illuminate\Support\Collection {#3353
     all: [
       {#3383
         +"id": 1,
         +"title": "Ola Database",
         +"body": "tinker",
       },
     ],
   }
>>> db::table('posts')->whereId(1)->get();
=> Illuminate\Support\Collection {#3382
     all: [
       {#3384
         +"id": 1,
         +"title": "Ola Database",
         +"body": "tinker",
       },
     ],
   }
>>> db::table('posts')->where(function($query){$query->where('id',1);})->get();
=> Illuminate\Support\Collection {#3401
     all: [
       {#3397
         +"id": 1,
         +"title": "Ola Database",
         +"body": "tinker",
       },
     ],
   }
  • operator 는 등호(=)일 경우, 생략이 가능하다.
  • whereId()는 종적 메서드다. 대등 조건에서만 사용할 수 있으며, 카멜표기법으로 가용 가능하다.
  • 클로저를 사용 가능 하다.

추가 메서드

메서드내용
insert(array $value)새 레코드 삽입
update(array $value)[‘column’=>’value’]처럼 연관 배열 인자를 넘겨 데이터를 변경한다
delete(int $id)$id에 해당하는 레코드를 삭제한다
pluck(string $column, string $key = null)인자로 지정한 열의 값으로만 구성된 콜렉션을 조회한다
limit(int $value)한 번에 조회할 레코드 개수를 제한한다
orderBy(string $column, string $direction = ‘asc’)조회 결과를 정렬한다. $derection에 허용되는 값은 ‘asc’ 또는 ‘desc’다

6.5 엘로퀀트 ORM

엘로퀀트는 러라벨이 제공하는 ORM의 구헌체 이름이다.

새로운 테이블을 생성한다

테스트 테이블 및 데이터 만들기

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
$ mysql -uhomestead -p
Enter password: 
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 30
Server version: 8.0.22 Homebrew

Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> use myapp;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

mysql> create table authors(
    -> id int(11) unsigned not null auto_increment primary key,
    -> email varchar(255) not null,
    -> password varchar(60) not null
    -> ) engine=innodb default charset=utf8 collate=utf8_unicode_ci;
Query OK, 0 rows affected, 3 warnings (0.01 sec)

mysql> insert into authors(email, password) values('test@gmail.com','test');
Query OK, 1 row affected (0.00 sec)

mysql> select * from authors;
+----+----------------+----------+
| id | email          | password |
+----+----------------+----------+
|  1 | test@gmail.com | test     |
+----+----------------+----------+
1 row in set (0.00 sec)

모델을 만들어 보자

모델 만들기

1
2
3
4
$ php artisan make:model Post
Model created successfully.
$ php artisan make:model Author
Model created successfully.

생성된 모델을 확인해 보자

app/Models/Post.php

1
2
3
4
5
6
7
8
9
10
11
12
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Post extends Model
{
    use HasFactory;
}

app/Models/Author.php

1
2
3
4
5
6
7
8
9
10
11
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Author extends Model
{
    use HasFactory;
}

테이블과 모델이름 테이블 이름은 복수로 짓고, 모델이름은 단수로 짓는다

테이블은 여러 개의 레코드를 가지고 있기 때문에 복수이고, 모델은 하나의 인스턴스를 담고 있기 때문에 단수를 쓰는 것이 상식적이다.
테이블과 모델 이름이 관례를 따르지 않을 때는 엘로퀀스에게 알려 주어야 한다. 테이블 이름을 user라고 했다면, Author 모델에게 protected $table = ‘user’; 처럼 사용할 테이블 이름을 알려 줘야한다

1
2
3
4
class Author extends Model
{
    protected $table = 'users';
}

모델 쿼리 팅커 콘솔에서 전체 콜렉션을 조회한다. DB 파사드가 아닌 [namespace][class명]모델을 이용한다.(위 예제에서는 App\Models\Author)

엘로퀀트 쿼리

1
>>> App\Models\Author::get();

새 모델 인스턴스를 만들고, 테이블에 저장해본다

엘로컨트로 새로운 레코드 만들기

1
2
3
4
5
6
7
8
>>> $author = new App\Models\Author;
=> App\Models\Author {#4231}
>>> $author->email = 'test@gmail.com';
=> "test@gmail.com"
>>> $author->password = 'test';
=> "test"
>>> $author->save();
Illuminate\Database\QueryException with message 'SQLSTATE[42S22]: Column not found: 1054 Unknown column 'updated_at' in 'field list' (SQL: insert into `authors` (`email`, `password`, `updated_at`, `created_at`) values (test@gmail.com, test, 2021-01-16 14:53:48, 2021-01-16 14:53:48))'

엘로퀀트는 updated_at, created_at 컬럼을 생성을 강제 한다. 하지만 테이블에 컬럼이 없기 때문에 에러가 발생 한다.

처리방법은 두가지로 1. 컬럼 생성, 2. 엘로컨트 타임스탬프 자동 입력 기능을 끄는 방법 이 있다

app/Models/Author.php

1
2
3
4
5
6
7
8
9
10
11
12
13
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Author extends Model
{
    public $timestamps = false;
    use HasFactory;
}

해당 변수확인 방법 부모 클래스(model)의 프로퍼티를 오버라이드 된것이다.

변경 후, tinker를 재시작 해야한다 30분 삽질 했다

재시도

1
2
3
4
5
6
7
8
>> $author = new App\Models\Author;
=> App\Models\Author {#3349}
>> $author->email = 'test@email.com';
=> "test@email.com"
>> $author->password = 'test';
=> "test"
>> $author->save();
=> true

데이터 저장

create() 메서드를 이용하면 새코드를 좀 더 편하게 만들수 있다

대량 할당

1
2
>>> App\Models\Author::create([                                                 'email'=>'test2@email.com',                                                     'password'=>bcrypt('test')                                                      ]);
Illuminate\Database\Eloquent\MassAssignmentException with message 'Add [email] to fillable property to allow mass assignment on [App\Models\Author].'

에러가 발생 한다. 위 에러는 무차별 대입 공격(brute force attack)을 막기위해 해당 형태로는 사용 못하 도록 막아 놓은 것이다

비말번호해시 bcrypt(string $value) 는 60바이트 단방향 패시를 만드는 도우미 함수다. 파사드로 사용시 hash::make(‘password’)로 사용 하면 된다.

MassAssingnmentException

엘로컨트는 무차별 대입 공격(brute force attack)를 방지하기 위하여 두가지 방법을 제공한다.

  • $fillable 프로퍼티를 이용하는 허용 목록(whitelist) 방식
  • $guarded 프로퍼티를 이용한 금지 목록(blacklist) 방식

아래 예제에서는 $fillable 방식을 사용한다.

app/Author.php

1
2
3
4
5
6
7
8
9
10
11
12
13
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Author extends Model
{
    public $timestamps = false;
    protected $fillable = ['email', 'password'];
    use HasFactory;
}

app/Post.php

1
2
3
4
5
6
7
8
9
10
11
12
13
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Post extends Model
{
    public $timestamps = false;
    protected $fillable = ['title', 'body'];
    use HasFactory;
}

팅커 콘솔을 재시작 후 실행해본다

재시도

1
2
3
4
5
6
7
8
Psy Shell v0.10.5 (PHP 7.3.11 — cli) by Justin Hileman
>>> App\Models\Author::create([                                                 'email'=>'test3@email.com',                                                     'password'=>bcrypt('test'),                                                     ]);
=> App\Models\Author {#4230
     email: "test3@email.com",
     password: "$2y$10$c/n4HsoX2Ne.0OVeKG8kGu9zZMPhhacJWvHw0WcId2ljolvyGtJz6",
     id: 3,
   }
>>> 
This post is licensed under CC BY 4.0 by the author.

라라벨로 배우는 php 웹 프로그래밍

자바스터디 9주차

Comments powered by Disqus.

Trending Tags