laravelrocksLaravel rocks는 Laravel 관련 팁을 모아 놓은 사이트입니다2024-03-19T20:29:51+09:00YongHun Byunhttp://twitter.com/rivertag:laravelrocks.com,2024:/feed.atomlaravel 5.4 새 기능tag:laravelrocks.com,2017-02-12:/tricks/laravel-5.4-new-features-2017-02-12T13:59:01+09:00<h4>동영상</h4>
<ul>
<li><a href="https://laracasts.com/series/whats-new-in-laravel-5-4">Laracast 무료 시리즈 - What's New in Laravel 5.4</a></li>
<li><a href="https://laracasts.com/series/laravel-from-scratch-2017">Laracast 무료 시리즈 - Laravel 5.4 From Scratch</a></li>
<li><a href="https://www.youtube.com/watch?v=sLrcpISBQec">Laravel 5.4 New Features - Part 1: All the Small Changes Overview</a></li>
<li><a href="https://www.youtube.com/watch?v=TeEsyhBZhUg">Part 2: Laravel Mix [Laravel 5.4 New Features]</a></li>
</ul>
<h4>articles</h4>
<ul>
<li><a href="https://scotch.io/tutorials/whats-new-in-laravel-5-4">What’s New in Laravel 5.4</a></li>
<li><a href="https://learninglaravel.net/laravel-54s-new-features-and-changes">Laravel 5.4's new features and changes!</a></li>
<li><a href="https://laravel-news.com/blade-prepend">Laravel Blade @prepend Directive</a></li>
<li><a href="https://laravel-news.com/relationship-macros">Laravel Eloquent Relationships Through Macros</a></li>
<li><a href="https://laravel-news.com/laravel-5-4-middleware">Laravel 5.4 Includes Two New Middleware</a></li>
<li><a href="https://mattstauffer.co/blog/introducing-laravel-dusk-new-in-laravel-5-4">Introducing Laravel Dusk</a></li>
<li><a href="https://mattstauffer.co/blog/introducing-laravel-mix-new-in-laravel-5-4">Introducing Laravel Mix</a></li>
<li><a href="https://medium.com/@codebyjeff/whats-new-in-laravel-5-4-collections-e55072fddfb0#.sevxrm62y">What’s New in Laravel 5.4 Collections</a></li>
<li><a href="http://themsaid.com/laravel-54-localization-json-20161117/">New in Laravel 5.4 - Localization using JSON files</a></li>
</ul>
console 로그와 웹 로그 분리하기tag:laravelrocks.com,2016-06-10:/tricks/configure-laravel-logging-2016-06-10T10:24:34+09:00<p>로그 설정을 <code>daily</code>로 하고, artisan command 등의 console 명령을 <a href="https://laravel.com/docs/master/scheduling">스케쥴링</a>을 통하여 수행하는 경우 console 계정과 웹 계정의 차이로 인해 다음의 문제가 발생하는 경우가 있다.</p>
<pre><code>Failed to open stream: Permission denied
</code></pre>
<p>원인은 스택오버플로우 <a href="http://stackoverflow.com/questions/27674597/laravel-daily-log-created-with-wrong-permissions">Laravel daily log created with wrong permissions</a>를 참고하면 될 것 같고, 이를 해결하기 위해 로그파일을 분리하는 방법을 정리해 봤다.</p>
<p><code>bootstrap\app.php</code></p>
<pre><code class="php">/*
|--------------------------------------------------------------------------
| Configure Monolog
|--------------------------------------------------------------------------
|
| console 유저와 웹 유저가 달라서 log 파일 접근시 권한 문제 발생해서 로그 파일 분리
| console에서 동작시 -artisan- 접두어가 붙은 로그 파일 사용
|
*/
$app->configureMonologUsing(function ($monolog) use ($app) {
$filePrefix = $app->runningInConsole() ? '-artisan' : '';
// debug 로그 파일 별도로 분리. 개발시 편리
if (config('app.debug', false)) {
$filename = storage_path('logs/laravel' . $filePrefix . '-debug.log');
$handler = new Monolog\Handler\RotatingFileHandler($filename, config('app.log_max_files', 5), Monolog\Logger::DEBUG);
$handler->setFormatter(new Monolog\Formatter\LineFormatter(null, null, true, true));
$monolog->pushHandler($handler);
}
$filename = storage_path('logs/laravel' . $filePrefix . '.log');
$handler = new Monolog\Handler\RotatingFileHandler($filename, config('app.log_max_files', 5), Monolog\Logger::INFO);
$handler->setFormatter(new Monolog\Formatter\LineFormatter(null, null, true, true));
$monolog->pushHandler($handler);
});
</code></pre>
<h2>관련글</h2>
<ul>
<li><a href="http://stackoverflow.com/questions/27674597/laravel-daily-log-created-with-wrong-permissions">Laravel daily log created with wrong permissions</a></li>
<li><a href="http://goodheads.io/2015/12/20/how-to-handle-logs-and-reports-in-your-app-using-laravel-5-part-2/">How to handle logs and reports in your app using Laravel 5 – Part 2</a></li>
<li><a href="https://github.com/mnabialek/laravel-sql-logger">Simple SQL Logger</a></li>
</ul>
Laravel 5에서 로깅 설정 변경하기tag:laravelrocks.com,2015-12-07:/tricks/custom-logging-in-laravel-5-2016-06-10T22:27:55+09:00<p><code>Illuminate\Foundation\Bootstrap\ConfigureLogging</code> 오버라이딩</p>
<p><code>bootstrap\ConfigureLogging.php</code> 생성</p>
<pre><code class="php"><?php namespace Bootstrap;
use Illuminate\Log\Writer;
use Illuminate\Contracts\Foundation\Application;
use Illuminate\Foundation\Bootstrap\ConfigureLogging as BaseConfigureLogging;
use Monolog\Processor\MemoryUsageProcessor;
use Monolog\Processor\WebProcessor;
class ConfigureLogging extends BaseConfigureLogging
{
/**
* Configure the Monolog handlers for the application.
*
* @param \Illuminate\Contracts\Foundation\Application $app
* @param \Illuminate\Log\Writer $log
* @return void
*/
protected function configureHandlers(Application $app, Writer $log)
{
parent::configureHandlers($app, $log);
$logger = $log->getMonolog();
// processor, adding URI, IP address etc. to the log
$logger->pushProcessor(new WebProcessor);
// processor, memory usage
$logger->pushProcessor(new MemoryUsageProcessor);
}
}
</code></pre>
<p><code>composer.json</code> 수정</p>
<pre><code>"autoload": {
...
"psr-4": {
"App\\": "app/",
"Bootstrap\\": "bootstrap/"
},
...
},
</code></pre>
<p><code>/app/Http/Kernel.php</code> 수정</p>
<pre><code><?php
...
use Illuminate\Contracts\Foundation\Application;
use Illuminate\Routing\Router;
...
...
public function __construct(Application $app, Router $router)
{
parent::__construct($app, $router);
array_walk($this->bootstrappers, function (&$bootstrapper) {
if ($bootstrapper === 'Illuminate\Foundation\Bootstrap\ConfigureLogging') {
$bootstrapper = 'Bootstrap\ConfigureLogging';
}
});
}
</code></pre>
<h2>관련글</h2>
<ul>
<li><a href="https://blog.muya.co.ke/configure-custom-logging-in-laravel-5/">Configuring Custom Logging in Laravel 5</a></li>
<li><a href="https://github.com/nztim/logger">nztim/logger</a></li>
<li><a href="https://github.com/rap2hpoutre/laravel-log-viewer">Laravel 5 log viewer</a></li>
</ul>
Lumen에서 daily log 사용하기tag:laravelrocks.com,2015-12-05:/tricks/daily-log-in-lumen-2015-12-07T00:03:11+09:00<p><code>Lumen</code>에서는 <code>storage/logs/lumen.log</code> 하나의 파일에 로그가 기록된다. 로그에 대한 설정은 <code>getMonologHandler</code>에서 행해진다.</p>
<p><code>Laravel\Lumen\Application</code></p>
<pre><code>...
/**
* Register container bindings for the application.
*
* @return void
*/
protected function registerLogBindings()
{
$this->singleton('Psr\Log\LoggerInterface', function () {
return new Logger('lumen', [$this->getMonologHandler()]);
});
}
/**
* Get the Monolog handler for the application.
*
* @return \Monolog\Handler\AbstractHandler
*/
protected function getMonologHandler()
{
return (new StreamHandler(storage_path('logs/lumen.log'), Logger::DEBUG))
->setFormatter(new LineFormatter(null, null, true, true));
}
...
</code></pre>
<p>날짜별로 로그를 기록하려면 <code>bootstrap/app.php</code>를 다음과 같이 수정하면 된다.</p>
<p><code>bootstrap/app/php</code></p>
<pre><code class="php"><?php
use Monolog\Handler\RotatingFileHandler;
use Monolog\Logger;
use Monolog\Processor\MemoryUsageProcessor;
use Monolog\Processor\WebProcessor;
...
/*
|--------------------------------------------------------------------------
| Register Container Bindings
|--------------------------------------------------------------------------
|
| Now we will register a few bindings in the service container. We will
| register the exception handler and the console kernel. You may add
| your own bindings here if you like or you can make another file.
|
*/
$app->singleton(
Illuminate\Contracts\Debug\ExceptionHandler::class,
App\Exceptions\Handler::class
);
$app->singleton(
Illuminate\Contracts\Console\Kernel::class,
App\Console\Kernel::class
);
/*
|--------------------------------------------------------------------------
| Configure logger
|--------------------------------------------------------------------------
*/
// Replace default log handler with daily log handler
$logger = $app->make('Psr\Log\LoggerInterface');
$logger->popHandler();
$logger->pushHandler(
(new RotatingFileHandler(storage_path('logs/lumen.log'), Logger::DEBUG))
->setFormatter(new LineFormatter(null, null, true, true))
);
// processor, adding URI, IP address etc. to the log
$logger->pushProcessor(new WebProcessor);
// processor, memory usage
$logger->pushProcessor(new MemoryUsageProcessor);
...
</code></pre>
<p><code>$logger->popHandler()</code>로 기본 로그처리기를 삭제하고, <code>$logger->pushHander()</code>를 이용해서 <code>RotatingFileHandler</code>를 등록한다.</p>
스키마 빌더에서 컬럼 주석 사용하기tag:laravelrocks.com,2015-11-26:/tricks/schema-column-comment-2015-11-26T10:41:29+09:00<p>스키마 작성시 <code>comment</code> 메서드를 사용하면 컬럼에 주석을 달 수 있다.</p>
<pre><code class="php">public function up()
{
Schema::create('posts', function(Blueprint $table) {
$table->increments('id')->comment('Unique identifier');
$table->string('title', 128)->comment('Title of the post');
$table->text('body')->comment('The entire content of the post');
$table->timestamps();
});
}
</code></pre>
로그인한 후 리다이렉트 되는 URL 변경하기tag:laravelrocks.com,2015-11-23:/tricks/redirect-url-after-login-2015-11-23T19:05:03+09:00<p>Laravel은 로그인이 성공한 뒤 <code>/home</code> 으로 라다이렉트한다. 이를 다른 URL로 변경하려면 <code>AuthController</code>에 <code>$redirectPath</code> 속성을 추가해서 지정하면 된다.</p>
<p><code>App\Http\Controllers\Auth\AuthController</code></p>
<pre><code>namespace App\Http\Controllers\Auth;
use App\User;
use Validator;
use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\ThrottlesLogins;
use Illuminate\Foundation\Auth\AuthenticatesAndRegistersUsers;
class AuthController extends Controller
{
protected $redirectPath = '/';
...
}
</code></pre>
<p>관련 로직은 <code>RedirectUers</code> trait에 있다.</p>
<p><code>Illuminate\Foundation\Auth\RedirectsUsers</code></p>
<pre><code class="php"><br /><?php
namespace Illuminate\Foundation\Auth;
trait RedirectsUsers
{
/**
* Get the post register / login redirect path.
*
* @return string
*/
public function redirectPath()
{
if (property_exists($this, 'redirectPath')) {
return $this->redirectPath;
}
return property_exists($this, 'redirectTo') ? $this->redirectTo : '/home';
}
}
</code></pre>
PasswordBroker 오버라이딩하기tag:laravelrocks.com,2015-11-23:/tricks/custom-passwordbroker-2015-11-23T12:32:21+09:00<p>비밀번호 리셋에 관련된 로직은 <code>Illuminate\Auth\Passwords\PasswordBroker</code> 클래스에서 수행이 되는데, 이 로직을 변경하고자 한다면 다음의 방법을 사용하면 된다.</p>
<h4>CustomPassowordBroker 생성</h4>
<p><code>Illuminate\Auth\Passwords\PasswordBroker</code>를 오버라이딩할 클래스를 생성하고 여기에 원하는 로직을 추가한다.</p>
<p><code>App\Services\CustomPasswordBroker</code></p>
<pre><code class="php"><?php namespace App\Services;
use Closure;
use UnexpectedValueException;
use Illuminate\Auth\Passwords\PasswordBroker;
use Illuminate\Contracts\Auth\PasswordBroker as PasswordBrokerContract;
use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
class CustomPasswordBroker extends PasswordBroker
{
...
}
</code></pre>
<h4>CustomPasswordResetServiceProvider 생성</h4>
<p><code>PasswordResetServiceProvider</code>을 확장한 <code>CustomPasswordResetServiceProvider</code>을 생성하고, 여기서 <code>CustomPassowordBroker</code> 인스턴스가 생성되도록 한다.</p>
<p><code>App\Prividers\CustomPasswordResetServiceProvider</code></p>
<pre><code class="php"><?php namespace App\Providers;
use App\Services\CustomPasswordBroker;
use Illuminate\Auth\Passwords\PasswordResetServiceProvider;
class CustomPasswordResetServiceProvider extends PasswordResetServiceProvider
{
/**
* Register the password broker instance.
*
* @return void
*/
protected function registerPasswordBroker()
{
$this->app->singleton('auth.password', function ($app) {
// The password token repository is responsible for storing the email addresses
// and password reset tokens. It will be used to verify the tokens are valid
// for the given e-mail addresses. We will resolve an implementation here.
$tokens = $app['auth.password.tokens'];
$users = $app['auth']->driver()->getProvider();
$view = $app['config']['auth.password.email'];
// The password broker uses a token repository to validate tokens and send user
// password e-mails, as well as validating that password reset process as an
// aggregate service of sorts providing a convenient interface for resets.
return new CustomPasswordBroker($tokens, $users, $app['mailer'], $view);
});
}
}
</code></pre>
<h4>config/app.php 수정</h4>
<p><code>Illuminate\Auth\Passwords\PasswordResetServiceProvider::class</code>을 <code>App\Providers\CustomPasswordResetServiceProvider::class</code>로 변경한다.</p>
<p><code>config/app.php</code></p>
<pre><code class="php">'providers' => [
...
App\Providers\CustomPasswordResetServiceProvider::class,
...
],
</code></pre>
blade의 @endsection 과 @stop 의 차이점tag:laravelrocks.com,2015-11-23:/tricks/blade-endsection-stop-2015-11-23T10:55:54+09:00<pre><code>@section('content')
@stop
</code></pre>
<p><code>blade</code>의 섹션을 닫을 때, <code>Laravel 3</code>에서는 <code>@endsection</code>, <code>Laravel 4</code>에서는 <code>@stop</code>으로 바뀐 걸로 알고 있었는데, <code>Laravel 5</code> 예제 소스들에서 <code>@endsection</code>이 보여서 둘 간의 차이점을 찾아봤다.</p>
<p><code>Illuminate\View\Compilers\BladeCompiler</code></p>
<pre><code class="php"> /**
* Compile the end-section statements into valid PHP.
*
* @param string $expression
* @return string
*/
protected function compileEndsection($expression)
{
return '<?php $__env->stopSection(); ?>';
}
/**
* Compile the stop statements into valid PHP.
*
* @param string $expression
* @return string
*/
protected function compileStop($expression)
{
return '<?php $__env->stopSection(); ?>';
}
</code></pre>
<p>두개가 같은 기능이다.</p>
Lumen, Laravel 겸용 패키지 만들기tag:laravelrocks.com,2015-11-06:/tricks/package-for-lumen-and-laravel-2015-11-06T12:08:24+09:00<p>패키지를 개발할 때, <code>Laravel</code>과 <code>Lumen</code>을 동시에 지원하고자 한다면, config 관련해서는 다음의 방법을 사용할 수 있다.</p>
<pre><code class="php">class SampleServiceProvider extends ServiceProvider
{
/**
* Bootstrap the application events.
*
* @return void
*/
public function boot()
{
$this->publishes([
__DIR__.'/../../config/config.php' => $this->getConfigPath(),
], 'config');
}
.
.
.
private function isLumen()
{
return str_contains($this->app->version(), 'Lumen');
}
private function getConfigPath()
{
if ($this->isLumen()) {
return base_path('config/mailgun.php');
} else {
return config_path('mailgun.php');
}
}
}
</code></pre>
최적화 명령어들tag:laravelrocks.com,2015-11-02:/tricks/optimization-commands-2015-11-02T15:11:06+09:00<p>최적화 명령어들</p>
<pre><code>php artisan optimize
php artisan config:cache
php artisan route:cache
</code></pre>
<p>최적화 명령어로 생성된 캐시 삭제 명령어들</p>
<pre><code>php artisan clear-compiled
php artisan config:clear
php artisan route:clear
php artisan view:clear
</code></pre>
<h4>관련글</h4>
<p><a href="http://sentinelstand.com/article/laravel-5-optimization-commands">Laravel 5 optimization commands</a></p>
특정 라우팅은 HTTPS 만 가능하게 하기tag:laravelrocks.com,2015-11-02:/tricks/routing-https-only-2015-11-02T14:53:05+09:00<p>특정 요청은 무조건 <code>https</code>로만 접근하게 하고자 할 때, <code>http</code>로 접속한 경우 <code>https</code>로 리다이렉트 하도록 하기 위해서 다음의 <code>Middleware</code>를 사용하면 된다.</p>
<p><code>app/Http/Middleware/ForceHttps.php</code></p>
<pre><code class="php"><?php
namespace App\Http\Middleware;
use Closure;
class ForceHttps
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
if (! $request->isSecure()) {
return redirect()->secure(
$request->getPathInfo() . ($request->getQueryString() ? ('?' . $request->getQueryString()) : '')
);
}
return $next($request);
}
}
</code></pre>
<p><code>app/Http/routes.php</code></p>
<pre><code class="php">Route::get('auth/login', ['middleware' => 'forcehttps', 'uses' => 'Auth\LoginController@getLogin']);
</code></pre>
URL과 쿼리스트링 구하기tag:laravelrocks.com,2015-11-01:/tricks/url-querystring-2015-11-01T16:58:14+09:00<p><code>http://example.com/test?foo=bar</code></p>
<pre><code>url() // http://example.com
</code></pre>
<pre><code>Request::getPathInfo() // /test
</code></pre>
<pre><code>Request::url() // http://example.com/test
</code></pre>
<pre><code>Request::fullurl() // http://example.com/test?foo=bar
</code></pre>
<pre><code>Request::getQueryString() // foo=bar
</code></pre>
updated_at 컬럼 사용하지 않기tag:laravelrocks.com,2015-11-01:/tricks/ignore_updated_at-2015-11-01T11:35:33+09:00<p><code>Laravel</code> <code>Eloquent</code>는 timestamp 컬럼인 <code>created_at</code>, <code>updated_at</code> 에 대해서 자동으로 날짜를 설정하고, 갱신하는 작업을 수행하다.</p>
<p>이 중 <code>created_at</code> 컬럼은 사용하고, <code>updated_at</code> 컬럼은 사용하지 않을 경우에는 다음의 메서드를 모델에 추가하면 된다.</p>
<pre><code class="php">public function setUpdatedAt($value)
{
// Do nothing.
}
</code></pre>
<p>참고로, 다음과 같이 하면 두 컬럼을 모두 사용하지 않는다고 설정하는 게 된다.</p>
<pre><code class="php">public $timestamps = false;
</code></pre>
<h4>관련글</h4>
<ul>
<li><a href="https://laravelrocks.com/tricks/19-timestamps-%EC%BB%AC%EB%9F%BC%EB%AA%85-%EC%A7%80%EC%A0%95%ED%95%98%EA%B8%B0">timestamps 컬럼명 지정하기</a></li>
<li><a href="https://laravelrocks.com/tricks/28-add-custom-timestamps-column">DB 테이블에 기본 timestamps 컬럼 외에 다른 날짜타입 컬럼 추가하기</a></li>
</ul>
개발 환경과 서비스 환경 쉽게 바꾸기tag:laravelrocks.com,2015-10-29:/tricks/environment-switch-2015-10-29T13:58:20+09:00<p><code>Laravel 5</code>에서 환경 설정 방법이 변경되서 개발 환경과 서비스 환경을 관리하기가 전 버전보다 귀찮은 것 같다. 그래서, 환경 설정 파일을 변경하는 스크립트를 만들어서 사용하면 좀 편하지 않을까 해서, PHP로 <code>envswitch</code>란 걸 만들었다.</p>
<p>이를 사용하기 위해서는 다음 형태의 폴더 구조를 가져야 한다.</p>
<p>폴더 구조 예</p>
<pre><code>├── config
│ └── queue.php
├── config_env
│ ├── queue.local.env
│ └── queue.production.env
├── .env
├── .env.local
└── .env.production
</code></pre>
<p>사용예</p>
<pre><code>./envswitch local
./envswitch production
</code></pre>
<p><code>envswitch local</code>을 실행하면 위의 폴더에서 <code>.env.local</code>이 <code>.env</code>로, <code>queue.local.env</code>가 <code>queue.php</code>로 복사된다.</p>
<h4>설치</h4>
<p>아래 소스를 복사해서 Laravel 루트 폴더에 envswitch 란 이름으로 파일을 만든 다음 실행권한을 주면 된다.</p>
<pre><code>chmod +x envswitch
</code></pre>
<p>envswitch 소스</p>
<pre><code class="php">#!/usr/bin/env php
<?php
if (count($argv) !== 2) {
echo "Missing required parameter envname\n";
echo "File should exist in current directory as .env.envname\n";
echo "Usage:\n";
echo " envswitch envname\n";
exit(1);
}
$env = $argv[1];
$envFile = ".env.$env";
if (! file_exists($envFile)) {
echo "$envFile does not exist.\n";
exit(1);
}
copyFile($envFile, ".env");
// config_env
foreach (glob("config_env/*.$env.php") as $filename) {
$srcFile = $filename;
$pathParts = pathinfo($srcFile);
$dstFile = $pathParts["basename"];
$dstFile = "config/" . str_replace(".$env.", ".", $dstFile);
copyFile($srcFile, $dstFile);
}
echo "Completed.\n";
function copyFile($src, $dst)
{
if (copy($src, $dst)) {
echo "Copied $src to $dst\n";
} else {
echo "Error occurred while copying $src to $dst\n";
exit(1);
}
}
</code></pre>
Laravel 5에서 DB 쿼리 로그 남기기tag:laravelrocks.com,2015-07-06:/tricks/laravel5-db-query-log-2015-07-06T19:49:59+09:00<p><code>Laravel 5</code>에서는 쿼리 로그가 기본적으로 비활성화 되어 있어서, 이전 버전처럼 바로 <code>DB::getQueryLog()</code>를 하면 빈 배열이 반환된다.</p>
<p>쿼리로그 활성화</p>
<pre><code>DB::enableQueryLog();
</code></pre>
<p>쿼리로그 얻기</p>
<pre><code>$queries = DB::getQueryLog();
</code></pre>