해리의 데브로그

The PHP Practitioner 03 - Boolean / Conditional / Function

|

Laracasts - The PHP Practitioner 강의를 듣고 정리한 포스팅 입니다.

1. Boolean & Conditional

Boolean은 조건문을 통해 여러가지 방법으로 표현이 가능함

  • 삼항 연산자: <?= $task['completed'] ? 'Complete' : 'Incomplete'; ?>
  • If/else if/else
  • Not: !true
<?php

$task = [
    'title' => 'Finish homework',
    'due' => 'today',
    'assigned_to' => 'jeffery',
    'completed' => false

]; // title, due, assigned_to,

require 'index.view.php';
</<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
    <h1>Task For The Day</h1>
    <ul>
        <?php foreach ($task as $heading => $value) :?>
        <li>
            <!-- ucwords: Capitalize first letter of each word -->
            <Strong><?= ucwords($heading); ?>: </Strong> <?= $value; ?>
        </li>
        <?php endforeach; ?>
    </ul>
    <ul>
        <li>
            <strong> Name: </strong> <?= $task['title']; ?>
        </li>
        <li>
            <strong> Due Date: </strong> <?= $task['due']; ?>
        </li>
        <li>
            <strong> Person Responsible: </strong> <?= $task['assigned_to']; ?>
        </li>
        <!-- Boolean 표현 1. 삼항 연산자 -->
        <li>
            <strong> Status: </strong> <?= $task['completed'] ? 'Complete' : 'Incomplete'; ?>
        </li>
        <!-- Boolean 표현 2. 일반 조건문(if/else) -->
        <li>
            <strong> Status: </strong>
            <?php
            if ($task['completed']) {
                echo 'Complete &#9989;';
            } else {
                echo 'Incomplete ';
            }
            ?>

        </li>
        <!-- 2-1. -->
        <li>
            <strong> Status: </strong>
            <?php if ($task['completed']) : ?>
                <span class="icon">&#9989;</span>
            <?php endif; ?>
        </li>
        <!-- 2.2. not 표현 -->
        <li>
            <strong> Status: </strong>
            <?php
                if (! $task['completed']){
                    echo 'Incomplete';
                }
            ?>
        </li>
    </ul>
</body>
</html>

2. Function

<?php

require 'function.php';
require 'index.view.php';

$animals = ['dog', 'cat'];

dd($animals);
// dd(['dog', 'cat']);

<?php

function dd($data) {
    echo '<pre>';
    die(var_dump($data));
    echo '</pre>';
}

The PHP Practitioner 02 - Arrays / Associative arrays

|

Laracasts - The PHP Practitioner 강의를 듣고 정리한 포스팅 입니다.

1. Understanding Arrays

array를 사용하면 loop에 매우 잘 활용할 수 있음

foreach($names as $name) {
    echo $name. ', ';
}

HTML과 결합할 경우 다음과 같이 사용 가능

  • {} 으로 묶어서 HTML 태그와 함께 쓰는 방법과,
  • <?php foreach() : ?> + <?php endforeach; ?>를 사용하는 2가지 방법이 있음.
  • HTML DOM 구조가 복잡해지며, 다양한 태그로 묶어야하는 경우가 발생한다면 2번째 방법이 더 선호 될 것임.
<?php

$names = [
    'harry',
    'ron',
    'max',
    'paul',
];

require 'index.view.php';
<!DOCTYPE HTML>
<html lang="en">
<head>
    <meta charset=UTF-8">
    <title>Document</title>
    <style>
        header {
            background: #e3e3e3;
            padding: 2em;
            text-align: center;
        }
    </style>
</head>
<body>
    <ul>
        <?php
            foreach ($names as $name) {
                echo "<li>$name</li>";
            }
        ?>
    </ul>
    <ul>
        <?php foreach ($names as $name) : ?>
            <li><?= $name; ?></li>
        <?php endforeach; ?>
    </ul>
</body>
</html>

2. Associative Arrays

Key:value의 형태로(마치 파이썬의 딕셔너리) 처럼 연관 배열을 만들 수도 있음

  • value만 사용하는 경우 : <?php foreach ($person as $feature) : ?>
  • key, value를 사용하는 경우 : <?php foreach ($person as $key => $value) : ?>
<?php

$person = [
    'age' => 31,
    'hair' => 'brown',
    'career' => 'web developer'
];

require 'index.view.php';
</<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
    <ul>
      	<!-- value만 출력하는 경우 -->
        <?php foreach($person as $feature) : ?>
            <li><?= $feature; ?></li>
        <?php endforeach; ?>

				<!-- key, value를 출력하는 경우 -->
        <?php foreach ($person as $key => $value) : ?>
            <li><strong><?= $key; ?></strong> <?= $value; ?></li>
        <?php endforeach; ?>
    </ul>
</body>
</html>

배열/연관배열에 데이터 추가하기 & 그외 팁

<?php

$person = [
    'age' => 31,
    'hair' => 'brown',
    'career' => 'web developer'
];

$animals = ['dog', 'cat'];

$person['name'] = 'harry'; # 연관배열에 데이터 추가
$animals[] = 'elephant'; # 일반배열에 데이터 추가

//echo $person; // echo는 string을 반환해야함. 배열에는 부적합

var_dump($person); // 배열 출력시 사용 literally dump the values
die(var_dump($person)); // php 코드를 die 시킴.
var_dump($animals);

The PHP Practitioner 01 - Variable / PHP and HTML / Seperate Logic

|

Laracasts - The PHP Practitioner 강의를 듣고 정리한 포스팅 입니다.

1. Variable

php -h #php 관련 명령어 확인가능
php -S <addr>:<port> # built-in web server 실행
php -S localhost:8888

basic formular: $변수명

<?php
$greeting = 'hello universe';
echo $greeting;
<?php
$greeting = 'Hello';
$name = 'Harry Lee';
echo $greeting. ' '. $name;
echo "$greeting, $name";
echo "{$greeting}, {$name}";

2. PHP and HTML

PHP와 HTML을 같이 쓸 경우에는 닫는 태그 ?> 가 반드시 필요함

<!DOCTYPE HTML>
<html lang="en">
<head>
    <meta charset=UTF-8">
    <title>Document</title>
    <style>
        header {
            background: #e3e3e3;
            padding: 2em;
            text-align: center;
        }
    </style>
</head>
<body>
    <header>
        <h1><?php echo 'Hello world';?></h1>
    </header>
</body>
</html>

p쿼리스트링이 url에 포함되는 경우(http://localhost:8000/?name=harry)

  • $_GET 을 사용하여 value값을 갖고 올 수 있음.
  • 해당 방법은 다음과 같이 확장/활용 가능. <?php<?=와 같이 shorthand로도 나타 낼 수 있음.
<h1>
  <?php
  	$name = $_GET['name']; # harry
  	echo "Hello, $name";
  ?>
</h1>
<h1>
  <?php echo "Hello, ". $_GET['name']; ?>
</h1>
<h1>
  <?= "Hello, ". $_GET['name']; ?>
</h1>

보안상의 문제? 누군가가 태그 자체를 입력하여 HTML을 수정하려 한다면? (http://localhost:8000/?name=<small>harry</small>)

  • Htmlspecialchar() 메서드를 사용
<h1>
  <?= "Hello, ". htmlspecialchars($_GET['name']); ?> 
  // 출력 값: Hello, <small>harry</small>
</h1>

3. Seperate PHP Logic From Presentation

Html: render Page & PHP: connect to DB, Add new data.

따라서 역할에 따라 두개의 파일들을 분리시키는 것이 가장 최적해임.

# index.html
<?php

$greeting = "Hello World";

require 'index.view.php'; 
<!-- index.view.php -->
<!DOCTYPE HTML>
<html lang="en">
<head>
    <meta charset=UTF-8">
    <title>Document</title>
    <style>
        header {
            background: #e3e3e3;
            padding: 2em;
            text-align: center;
        }
    </style>
</head>
<body>
<header>
    <h1>
        <?= $greeting; ?>
    </h1>
</header>
</body>
</html>

Laravel 5.7 From Scratch 13 - Authentication / Middleware

|

1. GET STARTED

라라벨 새 프로젝트 생성. Laravel new auth-example

웹 서비스에는 누구나 접근 가능하기보다는, authentification layer를 통해 허용된 유저만 접근이 가능해야함.

  • php artisan make:auth : Scaffold basic login and registration views and routes(only available below Laravel 6.0)
  • 라라벨 6.0 버젼 이후로는 아래의 명령어로 authentication을 위한 routes와 views를 생성할 수 있음
composer require laravel/ui --dev
php artisan ui vue --auth

2. Database 설정

이후 기본페이지에서 회원가입을 하면 database credential 설정을 하지 않았으므로 에러가 발생함.

Illuminate\Database\QueryException

SQLSTATE[HY000] [1045] Access denied for user ‘root’@’localhost’ (using password: NO) (SQL: select count(*) as aggregate from users where email = foo@example.com)

간단한 설정을 위해 .env 파일의 데이터베이스 설정을 sqlite로 변경후 database 디렉토리 내 database.sqlite 생성. 마지막으로 php artisan migrate 로 데이터베이스에 마이그레이션 설정한 후 다시 회원가입을 진행해보도록 하자.

DB_CONNECTION=sqlite
DB_HOST=127.0.0.1
DB_PORT=3306

3. Auth 살펴보기

php artisan tinker 로 유저목록을 확인해보면 회원가입된 회원정보를 알 수 있음.

>>> App\User::all();
=> Illuminate\Database\Eloquent\Collection {#3032
     all: [
       App\User {#3033
         id: "1",
         name: "foo",
         email: "foo@example.com",
         email_verified_at: null,
         created_at: "2019-12-09 06:24:34",
         updated_at: "2019-12-09 06:24:34",
       },
     ],
   }

Routes\web.php를 보면 Auth::routes() 가 추가된 것을 볼 수 있음. authentication에 대한 라우팅이 기본적으로 설정된 것으로 아래와 같이 두가지 방법으로 상세 정보를 확인 할 수 있음.

  1. php artisan route:list
  2. App\controllers\auth 내 생성된 컨트롤러 확인

Routes\web.php에 보면 /home 엔드포인트에 대하여 HomeController@index 를 호출하는 라우팅이 설정되어 있음. 이에 따라 HomeController.php를 살펴보면, 생성자 메서드로 middleware 메서드를 호출하는 것을 알 수 있음.

Route::get('/home', 'HomeController@index')->name('home');

<?php

namespace App\Http\Controllers;
use Illuminate\Http\Request;

class HomeController extends Controller
{
    public function __construct()
    {
        $this->middleware('auth');
    }
)

4. Middleware

미들웨어는 layers of Onion 처럼 이해하면 됨. 제일 안에 있는 layer로 가기 위해서는 바깥에 있는 layer들을 모두 거쳐야 함. App\Http\Kernel.php 에는 라라벨에 저장되어 있는 미들웨어의 목록을 볼 수 있음.

App\Http\Middleware\Authenticate.php를 살펴보면

  • Illuminate\Auth\Middleware\Authenticate as Middleware를 export 하는 것을 알수 있음.
  • Illuminate\Auth\Middleware\Authenticate.php는 미들웨어로서, 인증에 관한 로직을 구현해놓음.
  • 특히 handle 메서드를 통해 다음 미들웨어로 넘길 수 있음.
// Illuminate\Auth\Middleware\Authenticate.php

public function handle($request, Closure $next, ...$guards)
{
  $this->authenticate($request, $guards);

  return $next($request);
}

web.php를 보면 /home은 HomeController로 연결되어있으며, 이 클래스의 생성자는 middleware('auth')를 호출함. 여기서 middleware('auth') 는 App\Http\Kernel.php 내 $routeMiddleware 배열에 있는 auth 의 값을 호출 함.

// web.php
Route::get('/home', 'HomeController@index')->name('home');

// HomeController.php
public function __construct()
{
  $this->middleware('auth');
}

php artisan make:middleware 로 새로운 미들웨어를 생성하는 것도 가능함. 이후 kernel.php 내 미들웨어 배열안에 클래스를 추가하면 미들웨어로써 동작을 하게 됨.

5. You May Only View Your Projects

인스타그램, 페이스북 등과 같이, 내가 업로드한 프로젝트 리스트만 볼 수 있도록 설정하도록 하자. 유저 관련해서 다양한 메서드를 사용할 수 있음. 아래처럼 유저별로 프로젝트를 보여주기 위해서는 마이그레이션 & 스키마를 다시 설정해줘야함.

  • auth()->id() ex) 4
  • auth()->user() ex) user
  • auth()->check() ex) boolean
  • auth()->guest() ex) guest user
// ProjectsController.php
public function index()
{
  // $projects = Project::all();
  auth()->id(); // 4
  auth()->user(); // user
  auth()->check(); // boolean
  auth()->guest(); // guest user

  // select * from projects where owner_id = 4
  $projects = Project::where('owner_id', auth()->id())->get();

  return view('projects.index', compact('projects'));
}

6. Migration - Foreign key

\database\migration\create_project_table.php 내에서 owner_id 라는 새로운 컬럼 추가하며 방법은 2가지가 있음

  1. $table->unsignedBigInteger('owner_id')->index();
  2. $table->unsignedBigInteger('owner_id') & $table->foreign('owner_id')->references('id')->on('users'); owner_id 라는 외래키는 user 테이블의 id를 참조함.
    • 추가로 onDelete 설정도 가능함.

이후 php artisan migrate:fresh 를 통해 마이그레이션을 새로고침.

public function up()
{
  Schema::create('projects', function (Blueprint $table) {
    $table->bigIncrements('id');
    $table->unsignedBigInteger('owner_id');
    $table->string('title');
    $table->text('description');
    $table->timestamps();

    $table->foreign('owner_id')->references('id')->on('users')->onDelete('cascade');
  });
}

7. Authentication 설정

http://127.0.0.1:8000/projects/create 에 대한 사용자 인증을 진행하기 위해 기본 설정 진행. 로그인 사람만 해당 엔드포인트에 도달할 수 있도록 미들웨어를 추가할 수 있음.

composer require laravel/ui --dev
php artisan ui vue --auth
class ProjectsController extends Controller
{
  	// 생성자 메서드를 만들어, middleware('auth')를 추가시킴.
    public function __construct()
    {
        $this->middleware('auth');
    }

클래스의 특정 메서드에만 사용자 인증이 진행되도록 설정을 할 수 있음.

public function __construct()
{
  $this->middleware('auth');
  $this->middleware('auth')->only(['store','update']);
  $this->middleware('auth')->except(['show'])
}

클래스의 생성자 메서드에서 미들웨어를 호출하지 않고, 라우터에서 바로 호출하는 것도 가능함.

Route::post('/projects/{project}/tasks', 'ProjectTasksController@store')
  ->middleware('auth');

8. Controller - Add Foreignkey attribute

ProjectController@store 메서드에서 owner_id 를 추가해야함. 방법은 아래와 같이 2가지임

  1. Project::create($attribute + ['owner_id' => auth()->id()]);
  2. $attribute['owner_id'] = auth()->id();
// before
public function store()
{
  $attribute = request()->validate([
    'title' => ['required', 'min:3'],
    'description' => ['required','min:3'],
  ]);

  Project::create($attribute);

  return redirect('/projects');
}

// after
// option 1
public function store()
{
  $attribute = request()->validate([
    'title' => ['required', 'min:3'],
    'description' => ['required','min:3'],
  ]);

  Project::create($attribute + ['owner_id' => auth()->id()]);

  return redirect('/projects');
}

// option 2
public function store()
{
  $attribute = request()->validate([
    'title' => ['required', 'min:3'],
    'description' => ['required','min:3'],
  ]);

  $attribute['owner_id'] = auth()->id();

  Project::create($attribute);

  return redirect('/projects');
}

Laravel 5.7 From Scratch 12 - Configuration / Environment

|

1. GET STARTED

환경설정은 기본적으로 .env 파일에서 이루어짐. 그리고 config 디렉토리 내에 있는 파일들이 개별적으로 .env 파일의 내용을 호출하며 환경설정이 이루어짐.

.env 파일을 보안상의 목적으로 외부에 공개되면 안되므로 .gitignore에 추가하여 관리함. 따라서, development & production server의 .env 파일의 내용은 다름.

# development
APP_ENV=local
APP_DEBUG=true
SESSION_DRIVER=file

# production
APP_DEBUG=false
SESSION_DRIVER=reddis

2. exercise - call private key

설정된 private key를 호출하는 예시를 보도록하자.

Config\services.php 내에 key, value값 생성후 app\Providers\SocialServiceProvider.php에서 호출

// Config\services.php

return [

  // ... skip

'twitter' => [
  'key' => 'public-key',
  'secret' => 'secret-key'
],

// app\Providers\SocialServiceProvider.php
<?php

namespace App\Providers;

use App\Services\Twitter;
use Illuminate\Support\ServiceProvider;

class SocialServiceProvider extends ServiceProvider
{

    public function register()
    {
        $this->app->singleton(Twitter::class, function() {
            return new Twitter(config('services.twitter.secret'));
        });
    }
}

이후 web.php에서 서비스 컨테이너를 제대로 호출하는지 확인

<?php

use App\Services\Twitter;

Route::get('/', function(Twitter $twitter) {
    dd($twitter);

    return view('welcome');
});

3. Expand

Config\services.php 에서 고유 키값을 입력하는 것 보다, 고유값은 .env에서 입력한 후, 그 값을 불러오는 것이 더 효율적임

// Config\services.php
return [
    'twitter' => [
        'key' => env('TWITTER_KEY'),
        'secret' => env('TWITTER_SECRET')
    ],
],

//.env
TWITTER_KEY="public-key"
TWITTER_SECRET="secret-key"

새로운 configuration 파일을 만든 것도 가능함(in config directory)

<?php

return [
    'stripe' => [
        'private' => ''
    ]
];

// config('laracasts.strip.private')

Production 환경에서는 config 디렉토리 내 파일이 매우 많으므로 한 파일로 병합하는 것이 소스 코드를 불러 올때 빠름. development 에서는 사용할 필요 없음. this is for the purpose of performance optimization.

  • php artisan config:cache - Create a cache file for faster configuration loading
  • php artisan config:clear - clear a chahe file for faster configuration loading