Laravel로 프로젝트를 수행하면서 몰랐거나, 자주 헷갈리거나, 이해가 안되서 더 찾아봐야 하는 내용을 정리해 봤다. 써 보니 내 무지가 적나라하게 드러나는 것 같아 무척 창피하다. 이 글은 완성이 아니며 계속 수정될 거고, 잘못된 내용도 많을 것이다. 잘못된 내용은 편하게 지적해 주시기 바란다.

php

isset

배열에 관해서는 키가 없거나 값이 null 이면 false

$a = array ('test' => 1, 'hello' => NULL, 'pie' => array('a' => 'apple'));

var_dump(isset($a['test']));            // TRUE  
var_dump(isset($a['foo']));             // FALSE  
var_dump(isset($a['hello']));           // FALSE

// The key 'hello' equals NULL so is considered unset
// If you want to check for NULL key values then try: 
var_dump(array_key_exists('hello', $a)); // TRUE  

getIfSet

$a = isset($attrs['a']) ? $attrs['a'] : null);
$b = isset($attrs['b']) ? $attrs['b'] : null);
$c = isset($attrs['c']) ? $attrs['c'] : null);

getIfSet 함수를 써서 표현하면 훨씬 심플해 진다.

$a = getIfSet($attrs['a']);
$b = getIfSet($attrs['b']);
$b = getIfSet($attrs['c']);

function getIfSet(&$var) {  
    if (isset($var)) {
           return $var;
    }
    return null;
}

참고 : 왜 getIfSet의 인자를 call by reference를 썼을까?

method chain

class Foo {  
    public function methodA() {
        ...
        return $this;
    }

    pubilc function methodB() {
        ...
        return $this;
    }
}

위 처럼 메쏘드에서 $this를 반환하면 메쏘드 체인을 사용할 수 있다. 메쏘드 체인은 뭐냐? 시나리오, 프로세스의 연결.

new Foo()->methodA()->methodB();  

클래스 static 변수 초기화 방법

class Foo {  
  static $bar;
}
Foo::$bar = array(…);  

또는

class Foo {  
  private static $bar;
  static function init()
  {
    self::$bar = array(…);
  }
}
Foo::init();  

type hint

Type hints can not be used with scalar types such as int or string. Resources and Traits are not allowed either.

if statement

if 문의 다른 표현 방법

<?php  
if ($a == 5):  
    echo "a equals 5";
    echo "...";
elseif ($a == 6):  
    echo "a equals 6";
    echo "!!!";
else:  
    echo "a is neither 5 nor 6";
endif;  
?>

reference

다음의 결과를 예측해 보자. 이것 때문에 한참을 해멨다.

$foo = [‘a’ => array(), ‘b’ => array()];
$foo[‘a’][’hello’] = ‘world’;
var_dump($foo['a']['hello']);

$bar = $foo[‘b’];
$bar[‘hello’] = ‘world’;
var_dump($foo['a']['hello']);

$bar = &$foo[‘b’];
$bar[‘hello’] = ‘world’;
var_dump($foo['a']['hello']);  

closure

클로저에 변수를 넘기는 방법은?

Route::get(‘/‘, function() use($app) {  
     dd($app[‘files’]);
});

근데 다음처럼 쓰면 안되나? 역시 클로저를 이해 못하고 있는거야.

Route::get(‘/‘, function($app) {  
     dd($app[‘files’]);
});

문자열 처리는 Str 객체를 사용하라

  • strtolower 대신 Str::lower을 사용해라
  • MBCS, UNICDOE 처리 때문에

php snippet

swap을 하나의 라인으로 표시하면

list($max, $min) = array($min, $max);  

PHPDoc

@deprecated

/**
 * 폴 헬퍼 클래스
 *
 * @deprecated 임시로 asp에서 php로 변경하면서 만든 클래스이다. 사용하지 말어라.
 */

composer

require-dev는 뭔가?

Lists packages required for developing this package, or running tests, etc. The dev requirements of the root package are installed by default. Both install or update support the --no-dev option that prevents dev dependencies from being installed.

개발시 필요한 패키지와 서비스시 필요한 패키지를 구분하기 위해서.

app/start/global.php와 composer.json의 autoload의 차이점은?

  • composer.jsonLaravel과 상관없는 내용.
  • app/start/global.phpLaravel에서 사용할 수 있는 autoload.
  • Laravel 입장에서는 중복 같다. deploy를 생각한다면 start.php가 더 좋아 보인다.

artisan

php artisan tinker

environment

getenv 함수

getenv(‘key’)

환경설정 파일

.env.local.php
.env.production.php
.env.php
<?php  
return [  
     ‘key’ => ‘value’
];

input

input 값 바꾸기

Input::merge(array('key' => 'value'));  
Input::replace(array('key' => 'value'));  

session

  • 특정 라우트에 대해서 세션을 사용하지 않게 하는 방법은 ?

Routing

"Route pattern "/product/related-self/{any}/{id}/{any}" cannot reference variable name "any" more than once” 오류 해결 방법

Route::get('/product/related-self/{any}/{id}/{any}', array('as' => 'products.related.self', 'uses' => 'ProductsController@getRelatedSelf'));  

위 오류가 나서 임시로

Route::pattern('any', '[^\/]+');  
Route::pattern('any2', '[^\/]+’);

Route::get('/product/related-self/{any}/{id}/{any2}', array('as' => 'products.related.self', 'uses' => 'ProductsController@getRelatedSelf'));  

Routing 예제

두 개의 url 세그먼트에 각각 패턴 지정하기

Route::get('save/{princess}/{unicorn}', function($princess, $unicorn)  
{
    return "{$princess} loves {$unicorn}";
})->where('princess', '[A-Za-z]+')
  ->where('unicorn', '[0-9]+');

routing 패턴 정할 때 사용하는 이름과 실제 호출되는 함수나 메소드의 인자 이름은 별개다. 당연하 얘기겠지만.

Route::get('/foo/{id1}/{id2}', function($arg1, $arg2) {  
    echo "arg1=$arg1, arg2=$arg2";
});

Eloquent

  • composite primary key
class OrderCatalog extends Model {  
    protected $table = 'Foo';
    protected $primaryKey = array('pk1', 'pk2');
}
  • 쿼리 예제
   return DB::table('tmn_catalog')
        ->select(array('tmn_catalog.*', DB::raw('(SELECT Count(*) FROM TMN_OrderCatalog WHERE CatalogID = tmn_catalog.CatalogID) AS OrderCnt')))
        ->where('tmn_catalog.catalogid', '=', $id)
        ->first();

적색으로 표시한 부분 중요하다. 그 부분이 있어야 hasOne 관계를 통해서 연결을 맺을 수 있다.

   public function count_orders() {
        return $this->hasOne('Trademall\OrderCatalog', 'CatalogID', 'CatalogID')
            ->groupBy('CatalogID')
            ->select('CatalogID', \DB::raw('count(*) AS OrderCnt')
        );
    }
    => select [CatalogID], count(*) AS OrderCnt from [TMN_OrderCatalog] where [TMN_OrderCatalog].[CatalogID] in ('360680') group by [CatalogID]
    public function getOrdersByCatalogIds($catalog_ids) {
        return $this->model->whereIn('catalogid', $catalog_ids)
            ->groupBy('catalogid')
            ->get(array('CatalogID', \DB::raw('count(*) as OrderCnt')));
    }
    => select [CatalogID], count(*) as OrderCnt from [TMN_OrderCatalog] where [catalogid] in ('10', '20') group by [catalogid]

Eager Loading

  • Eager Loading을 사용하면 Repository 사용을 줄일 수 있다.

Eloquent Relationship

  • function 이름과 모델이름이 같을 필요는 없다.
     public function images() {
        return $this->hasMany('Trademall\CatalogImage', 'CatalogID', 'CatalogID');
    }

DBMS

MSSQL

freetds의 오류 메시지가 null로 보인다.

Design Pattern

한번 감싸라...

class MyLog {

    public static function error($message) {
        \Debugbar::error($message);
    }

    public static function warning($message) {
        \Debugbar::warning($message);
    }

    public static function notice($message) {
        \Debugbar::notice($message);
    }

    public static function info($message) {
        \Debugbar::info($message);
    }
    public static function debug($message) {
        \Debugbar::debug($message);
    }

}

Repository 리턴은 Model이냐 Array냐

Eloquent와의 종속적인 부분을 줄이기 위해서 Array를 반환하라고 하는데, Array로 반환을 하면 다음이 불편함.

  • $user['name’] 형태의 작업을 해야 함
  • Presenter를 사용하지 못함

Repository는 테이블별로 만들어야 하나?

  • 조인은 어떻게 처리를 하지?

helper나 basic function은 어디에 두는 게 좋을까?

helper는 view단에서 쉽게 쓸 수 있어야 한다.

첫번째 방법 : Facade로 만드는 방법

두번재 방법 : libraries 또는 helper 폴더를 만들어서 여기에 두는 방법

blade 관련

다음 두개의 문장은 동일하다.

@section(‘page_title’, ‘TradeMall’)

@section('page_title')
TradeMall  
@stop

@section 내부의 변수

@section 내부의 변수는 공유된다.

@section('a')
{{ $foo }}
@stop

@section('b')
<?php $foo = 'bar';?>  
{{ $bar }}
@stop
  • 위 결과는 undefined variable
  • @section 두개를 바꾸면 오류가 나지 않는다.
  • @section은 순서대로 실행이 되고 그 결과는 내부 변수에 저장되고 이는 @yield를 통해서 접근 가능 (내 추정)

좀 생각을 해보니 @section 내부의 변수라는 말 자체가 틀린 것 같다. @section은 컴파일한 결과를 보면 그냥 함수의 호출로 변경되고, 따라서 @section@stop이 어떤 블럭을 형성하는 게 아니라 그냥 같은 스코프 문장의 연속이라고 보는 게 맞을 것 같다. @section 내부의 변수가 아니라 @section 다음에 오는 변수 관련 문장으로 보면 될 것 같다.

blade 에서 use를 사용하는 게 맞는가?

  • IDE의 도움(인텔리센스)을 전혀 받지 못함
  • 뭔가 코드가 정돈되지 않은 느낌
  • 맞지 않다는 결론

view 단에서 반복되는 코드는 어떻게 해결할까?

  • 화면 출력이면 partial view로 빼서 include 한다.
  • Presenter로 뺀다.
  • 공통 유틸성이면 helper 클래스로 뺀다.

Package

Carbon

  • nesbot\carbon

Carbon Class not found 오류가 나는 경우

Carbon\Carbon::createFromFormat('Y-m-d H:i:s', $this->resource->published_at, 'Europe/Berlin') ->toFormattedDateString();

debugbar

  • 에러로그는 파일로 남나?

darsain/laravel-console

/console 접속시 notfound 오류 발생

$ php artisan config:publish darsain/laravel-console

config/packages/darsain/laravel-console/config.php 수정

'whitelist' => array('127.0.0.1', '::1', '192.168.33.1'),  

Related Articles