[1일 1식 라라벨] 라라벨 Vapor

이 글은 2019년 7월 29일에 1일 1식 라라벨에 발행된 글입니다. 일부 시점이나 버전 정보가 블로그 발행시점과 다를 수 있습니다.

지난 주 라라콘에서 라라벨이 새로운 서비스를 소개했습니다. 바로 Vapor 입니다. “서버는 우리가 다 알아서 해줄게요, 여러분은 라라벨 애플리케이션에만 신경쓰세요”라고 이야기하는 것 같습니다. 매트 스타우퍼가 라이브 블로깅으로 정리한 라라벨 Vapor 소개(Introducing Laravel Vapor)와 모하메드 새드의 AWS 람다란 무엇이고, 라라벨 Vapor가 이를 어떻게 사용하는가(What is AWS Lambda, and how Laravel Vapor uses it)를 요약해서 소개하겠습니다.

동기

라라벨은 포지(Forge)라는 배포 서비스를 가지고 있습니다. 포지를 사용하면 AWS, DigitalOcean, Linode 같은 클라우드 서버에 애플리케이션을 쉽게 배포할 수 있습니다. 편리한 서비스이지만 사람들이 오토 스케일링 같은건 어떻게 해야하는지 문의했나봅니다. 이에 대해 라라벨팀은 포지에 오토스케일링 기능을 추가하는 대신 새로운 접근 방법을 택했습니다. 바로 서버리스입니다.

서버리스 (Serverless)

서버리스는 말그대로 서버가 없다는 뜻입니다. 하지만 정말로 서버가 없는건 아니죠. 실제로 어딘가에 서버가 존재는 하지만 나는 그 존재를 알 필요가 없다는 것입니다.

라라벨의 index.php 파일을 열어보면 아래 내용을 볼 수 있습니다. (전에 리퀘스트 라이프 사이클에서도 다뤘던 내용이죠! ^^)

$response = $kernel->handle(
  $request = Illuminate\Http\Request::capture()
);

$response->send();

애플리케이션에 리퀘스트를 보내면 Kernel::handle 메소드가 처리하고 브라우저에게 리스폰스를 되돌려줍니다. 그동안은 이를 위해 서버를 마련하고 어떤 요청이 들어오던 index.php를 실행하도록 준비하고 기다리고 있었습니다.

Kernel::hanle 메서드만 똑 떼어내서 어떤 서비스에 올려놓고, 메서드가 실행되는 횟수만큼만 비용을 낸다면 어떨까요? 서버에 배포하거나, 라이브러리를 업그레이드하거나, 저장공간을 관리하는데 전혀 신경안써도 됩니다. 단지 기능을 업로드하고 기능이 동작하는만큼만 돈을 내는 것이죠.

이게 기본적인 서버리스입니다.

AWS 람다(Lambda)

람다는 AWS의 FaaS(Function as a Service)입니다. 람다는 주로 마이크로서비스 아키텍처의 일부로 사용되며, 한 번에 한 가지 일을 처리합니다.

  • 이미지를 S3에 올리면 섬네일을 만든다.
  • 큐에 잡을 전송하면, 람다가 실행되고 잡을 처리한다.
  • HTTP 리퀘스트를 엔드포인트로 전송하면, 람다가 실행되고 응답을 생성한다.

이런 식입니다. 이는 일반적으로 애플리케이션을 애플리케이션을 여러개의 서로 다른 서비스로 쪼개고, 각 서비스는 개별 코드 베이스를 갖는 것을 의미합니다.

마이크로서비스는 장점이 많지만 여러 서비스를 엮는게 어렵습니다.

Vapor는 여러분의 라라벨 애플리케이션을 AWS 람다로 변환합니다. 람다를 실행한 이벤트에 따라 Vapor가 애플리케이션의 특정 기능을 수행해줍니다. 사용자가 엔드포인트를 방문하면 라우터로 보낸 후 응답을 되돌려주고, 잡이 추가되면 워커를 작동시키는 식입니다. 이런식으로 라라벨 애플리케이션 작성 방법은 그대로 유지한채 서버리스의 장점을 취할 수 있습니다. Vapor가 라라벨 애플리케이션을 서버리스로 변환하는데 필요한 모든 일을 해줍니다.

마치며

그냥 단순히 배포와 오토스케일링을 처리해주는 서비스인가?라고 생각했는데 라라벨을 서버리스로 변환해주고 편하게 관리할 수 있게 해주는 서비스였네요. 정말 엄청나네요! AWS 비용이 얼마나 나올지 가늠이 안되긴하는데 저는 서비스가 정식 오픈 하는대로 한 번 써볼까 합니다. Vapor 자체는 프로젝트 수에 상관없이 한달에 39$라서 크게 부담은 안되는 듯 합니다.

[1일 1식 라라벨] 라라콘 US 2019 발표자들

이 글은 2019년 7월 25일과 26일에 1일 1식 라라벨에 발행된 글입니다. 일부 시점이나 버전 정보가 블로그 발행시점과 다를 수 있습니다.

라라벨 진영의 가장 큰 행사인 LARACON US 2019가 오늘 시작됐습니다. 올해 8월에 라라벨 6가 나온다는 발표도 있었고 Vapor 라는 서버리스 플랫폼을 새로 출시했네요. 아직 자료나 동영상 등이 많이 공유되진 않고 있어서, 좀 더 자세히 알게되면 다시 공유하겠습니다. 대신 오늘은 LARACON US 2019 발표자들을 간단히 소개해볼까해요. 원래는 발표 주제도 공유하고 싶었는데, 이번 LARACON은 발표 제목이 공개되지 않았어요. 아쉽지만 어떤 인물들이 등장했는지만 알아보겠습니다. 인물이 꽤 많으니 컨펀런스 일정에 따라 첫째 날 둘째 날로 두 편에 나누어 쓰겠습니다.

LARACON US 2019 연사 Day 1

아담 와든 Adam Wathan

7월 20일자 1일 1식 라라벨에 등장했던 인물이군요. TailwindCSS를 만든 사람입니다. 작년 재작년 발표 모두 좋았는데, 올해 또 등판했네요. 홈페이지에서도 확인할 수 있겠지만 TailwindCSS 뿐만 아니라 라라벨과 뷰 관련 강좌와 도서도 많이 만들었습니다. Full Stack Radio라는 팟캐스트도 운영하고 있어요. 프론트엔드, 백엔드 모두 능통하고 발표까지 잘하는 난 사람이네요.

프릭 반 더 허르텐 Freek Van Der Herten


스파티 Spatie의 공동대표입니다. 스파티는 벨기에에 있는 웹 에이전시인데, 라라벨용 패키지를 엄청 많이 만들어 공개하고 있고, 구성원들로 하여금 지식 공유를 적극 권장하는 것으로 보입니다. 스파티의 패키지는 테일러 오트웰도 종종 트위터에서 언급하곤 합니다. 라라벨에 관심있는 사람이라면 스파티가 내놓은 패키지들이 뭐가 있는지 살펴보는게 도움이 될 것입니다. 프릭은 블로그를 통해 지식을 활발히 공유하고 있고, 뉴스레터도 발행하고 있습니다. 최근에 Oh Dear!라는 웹사이트 모니터링 서비스를 오픈하기도 했습니다.

바비 엘리트 바우만 Bobby Elite Bouwmann

이번 LARACON에서는 라라벨 디자인 패턴에 대해 발표했나봅니다. 이전 LARACON에서 발표했던 디자인 패턴 1.0 발표는 여기(슬라이드 쉐어유튜브)에서 볼 수 있습니다. markdownmail.com를 운영하고 있습니다. 공식 메뉴얼에 없는 숨겨진 기능들을 소개하는 라라벨 시크릿이라는 책을 쓰고 있다고 하네요.

제이슨 맥크레리 Jason McCreary

약간의 비용만 내면 내 프로젝트의 라라벨 버전을 올려주는 서비스인 라라벨 시프트를 만든 사람입니다. 자본주의 만세! 물론 사람이 해주는건 아니고 자동화되어있습니다. GettingGit과 BaseCode라는 강좌를 판매하고 있습니다. BaseCode는 읽기 좋은 코드를 작성하는 10가지 비법을 알려준다는데 저도 흥미가 가네요.

케이스 대미아니 Keith Damiani

타이튼 Tighten 소속 개발자입니다. 타이튼도 스파티와 마찬가지로 오픈소스 활동과 지식 공유 활동을 활발히 하는 에이전시입니다. 요즘에는 그래프 데이터베이스와 모바일 앱개발에 관심이 많다고 합니다. 이번 라라콘에서도 라라벨과 그래프 데이터베이스라는 주제로 발표를 하는 것 같네요.

카야 토마스 Kaya Thomas

명상앱을 만드는 Calm에 소속된 iOS 개발자입니다. 사이드 프로젝트로 We Read Too를 개발했습니다. We Read Too는 2014년에 런칭됐고, 2018년 2월에 애플 스토어에 피쳐드 된 바 있다고 하네요. 이번 행사에서는 풀 타임으로 일하면서 사이드 프로젝트를 런칭하고 운영하기라는 주제로 발표를 한 듯 합니다.

조나단 레이닝크 Jonathan Reinink

PHP를 쓸 땐 라라벨을 주력 프레임워크로 사용하는(라라벨 행사의 연사니 당연한 얘긴가요 ^^;) 웹 개발자입니다. Church Social이라는 서비스를 운영하고 있습니다. 오픈소스 활동로 Glide라는 이미지 조작 라이브러리와 Plates라는 템플릿 엔진을 만들었습니다. 그리고 아담 와든과 함께 TailwindCSS를 만들었네요! 요즘에는 서버 주도 SPA를 만드는 InertiaJS라는 자바스크립트 프레임워크를 만들고 있다고 합니다. 최근에 엘로퀀트 퍼포먼스 패턴이라는 비디오 강좌를 만들었는데, 이번 행사에서는 이와 관련된 발표를 했나봅니다. 발표를 들은 테일러 오트웰이 “엘로퀀트에 대해선 레이닝크가 나보다 낫다”고 했네요. 위에 등장했던 프리크 반 더 허르텐도 레이닝크가 블로그로 소개한 테크닉을 써봤더니 좋더라는 트윗을 올린걸로 봐선 확실히 실력이 좋고 엘로퀀트를 더 좋은 성능으로 사용하는 노하우가 있나봅니다.

저스틴 잭슨 Justin Jackson

팟캐스트 플랫폼 Transistor.fm을 창업했습니다. MegaMaker라는 부트스트래퍼(투자 받지 않고 개발해서 제품으로 소득을 올리는) 커뮤니티도 운영 중입니다. 개발자를 위한 마케팅(Marketing for Developers)과 Jolt라는 책을 썼습니다.

LARACON US 2019 연사 Day 2

콜린 디카를로 Colin Decarlo

Vehikl 이라는 웹 에이전시 소속 개발자입니다. 이번 행사에서 발표한 주제는 “나는 웹 개발에 필요한 모든 것을 트위터 타임라인에서 배웠다”였다고 하네요.

스티브 쇼거 Steve Schoger

스티브 쇼거는 디자이너로서 아담 와든과 함께 RefactoringUI를 저술했습니다. UI에 요긴하게 쓸 수 있는 디자인용 에셋인 Hero PatternsHeroiconsZondicons 프로젝트를 진행하고 있습니다. Hero Patterns와 Zondicons는 무료, Heroicons는 유료인거 같네요. 이번 행사 발표 주제는 비쥬얼 디자이너 처럼 생각하는 법이었네요.

에반 유 Evan You

VueJS의 창시자입니다. 구글에서 일하면서 만든 VueJS가 대히트를 쳐서 현재는 풀타임 오픈 소스 개발자로 생활하고 있습니다. Patreon에서 밝힌 바에 따르면 Patreon에서 한 달에 16,000달러(한화로 약 2,000만원)를 번다고 하네요. 라라콘의 단골 연사 중 한 명입니다. 2016년부터 올해까지 한 해도 빠지지 않고 발표를 한 것 같습니다. 이번 행사에서는 Vue v3.0에 어떤게 추가될 건지 발표한 것 같네요.

마르셀 포시오트 Marcel Pociot

라라벨 전문 개발사인 Beyond Code에서 매니징 및 개발자로 일하고 있고 PHP 챗봇 프레임워크인 BotMan을 만들었습니다. 최근에 자신의 라라벨용 패키지들의 총 다운로드 수가 1,000만이 넘었다고 합니다. 굉장하네요. 최근에 패키지 개발 방법 동영상 강좌을 출시했습니다. 이번 라라콘 발표도 패키지 개발 방법에 관한 내용이었던 것 같아요. 이 강좌는 현재 오픈 기념 40% 세일 중이라고 하네요.

칼렙 포르지오 Caleb Porzio

Livewire 개발자 입니다. Livewire는 라라벨용 풀스택 프레임워크인데, 순수 PHP를 쓰듯 간단하게 동적 프론트 엔드를 만들어 준다고 합니다. 이번 행사에서 공개한 것 같은데, 트위터를 통해서 느껴지는 반응이 심상치 않네요.

카트리나 트라예브스카 Katerina Trajchevska

원격 근무 개발자이자 개발자 채용 서비스 Adeva의 공동 창업자 입니다. Time Driven Development라는 제목으로 발표했네요.

크리스토프 럼펠 Christoph Rumpel

라라벨 코어 어드벤처의 저자입니다. 말그대로 라라벨의 코어를 파헤치는 동영상 강좌입니다. 원래는 무료였는데, 막상 해보니 시간과 에너지가 너무 많이 들어서 유료로 전환했다고 합니다. 현재는 라이프 사이클, 파사드, 엘로퀀트, 서비스 컨테이너를 다루는 컨텐츠가 준비되어 있고, 알림과 테스팅은 준비 중이네요. 이번 행사에서는 자신의 컨텐트인 라라벨 코어 어드벤처를 소개했나 봅니다. 라라벨 코어 어드벤처는 그 전에는 챗봇 관련 도서를 쓰고 강좌도 만들었다고 합니다.

드라이스 빈츠 Dries Vints

2018년 9월에 라라벨에 입사했습니다. http://laravel.io 를 관리한다고 하네요. 벨기에 엔트워프에 살고 Full Stack Belgium과 Full Stack Europe 이라는 모임을 주관한다고 합니다. 이번 행사에서는 EVENT SAUCING IN LARAVEL WITH EVENTSAUSE라는 주제로 발표를 했나 봅니다. 이벤트소스(EventSauce)는 프랭크 드 종(Frank de Jonge)이라는 개발자가 만든 PHP용 이벤트 소싱 라이브러리라고 하는데, 저한테는 아직 생소한 개념이네요. 공부해야겠어요 ㅠ 스파티의 프리크 반 더 허르텐이 이미 라라벨용 이벤트 소스 패키지도 내놨더군요. 암튼 새로 대두되는 주요 개념인것 같은 느낌입니다.

매트 스타우퍼 Matt Stauffer

타이튼의 기술 분야 리더입니다. Laravel Up & Running이라는 책(저와 익명의 공동 번역자가 함께 번역 중입니다. 한빛미디어를 통해 내년 초에 출간 예정이에요 ^^)의 저자이고 라라벨 팟캐스트5분 긱 쇼 등을 진행하고 있습니다. 라라벨 뉴스를 발행하고 있기도 하고요. 이번 행사에서 Onramp라는 학습 가이드를 소개한 듯 합니다. 살짝 봤는데 좋네요. 컨텐츠가 영어인게 아쉽습니다.

이상으로 라라콘 US 2019 2일차 연사를 모두 소개했습니다. 많은 분들이 현업에 종사하기도 하지만 오픈 소스 활동과 지식/정보 사업을 주로 하는 분들도 많아서 부럽네요. 한국도 오픈소스 활동만으로, 혹은 컨텐트 생산 및 지식 전달 활동만으로도 잘 먹고 잘 살 수 있는 나라가 되면 좋겠어요. 여튼 화이팅 하는 걸로!

[1일 1식 라라벨] ERD를 그려주는 Laravel ER Diagram Generator

이 글은 2019년 7월 15일에 1일 1식 라라벨에 발행된 글입니다. 일부 시점이나 버전 정보가 블로그 발행시점과 다를 수 있습니다. 8월호 구독자를 모집하고 있습니다. 월 1만원으로 최신 라라벨 소식을 받아보세요.

충분한 여유를 가지고 프로젝트를 진행한다면 코드를 작성하기 전에 설계도 하고, ERD(Entity Relation Diagram)도 그리고 할 것이다. 하지만 세상은 언제나 나에게 호의적이지만은 않다. 사전에 계획 문서를 충분히 작성할 시간이 부족한 프로젝트를 맡게 될 수도 있고, 처음엔 그리 복잡하지도 않고 혼자 진행해서 문서를 만들지 않고 진행했을 수도 있다. 그런데 이후에 클라이언트가 문서를 요구하거나, 혹은 동료가 더 생겨서 코드를 빠르게 파악하는데 도움이 되는 문서가 필요해지는 경우가 있다. Laravel ER Diagram Generator는 이런 경우에 요긴하게 쓸 수 있는 패키지이다.

Laravel ER Diagram Generator는 모델 파일에 정의된 관계를 분석해서 ERD를 생성한다. 다음은 Laravel ER Diagram Generator로 생성한 Laravel.io의 ERD이다.(출처:  공식 저장소)

설치

우선 PHP 7.1 이상이 필요하고, graphviz가 설치되어 있어야 한다.

brew install graphviz

홈스테드

sudo apt-get install graphviz

윈도우 환경이면 공식 웹사이트에서 다운로드 한다.

패키지는 컴포저로 설치한다.

composer require beyondcode/laravel-er-diagram-generator --dev

개발에만 필요하고 프로덕션 환경에는 필요 없다. --dev 옵션을 잊지 말자.

사용

아티즌 커맨드로 사용한다.

php artisan generate:erd

옵션과 커스텀 설정은 저장소 문서를 참고하자.

소감

트위터에 코드를 먼저 짜고 분석을 나중에 하냐는 조롱조의 글도 있다. 하지만 앞서 언급한 것 처럼 내 손에 넘어오는 시점에 어떠한 문서도 없이 코드만 달랑 넘어오는 경우가 분명히 있고, 이럴 때는 코드를 기반으로 문서를 만들어주는 도구가 유용하게 쓰일 수 있다. 실무적인 용도 외에 학습용으로도 꽤 유용할 수 있다. 타인의 코드로 학습하기 때문에 코드에서 부터 분석을 시작할 수 밖에 없기 때문이다.

조금 아쉬운 점은 엘로쿼트 모델을 상속받은 엔티티만이 분석 대상에 포함된다는 점이다. 도메인 주도 개발을 지향하거나, 클린 아키텍처를 지향하는 경우 라라벨에 의존하지 않는 도메인 모델과 서비스를 핵심으로 삼을 수도 있는데, 이러면 이 패키지로는 분석이 불가능하다.

[1일 1식 라라벨] 특정 버전의 라라벨 설치하기

이 글은 2019년 7월 4일에 1일 1식 라라벨에 발행된 글입니다. 일부 시점이나 버전 정보가 블로그 발행시점과 다를 수 있습니다. 8월호 구독자를 모집하고 있습니다. 월 1만원으로 최신 라라벨 소식을 받아보세요.

며칠 전에 라라벨 5.8.27이 나왔다. 새로 설치하는 사람이라면 특별한 이유가 없는 한 최신 버전을 설치하는게 좋다. 메뉴얼에서 안내하는 대로 설치하면 자연히 최신 버전이 설치된다. 하지만 어떠한 이유에서건 과거의 버전을 설치할 필요가 생길 수 있다.

구글에서 laravel install specific version 으로 검색하면 특정 버전의 라라벨을 설치하는 방법을 어렵지 않게 찾을 수 있다.

문제는 저 글들이 공통적으로 알려주는 방법으로는 내가 원하는 정확한 버전을 설치할 수 없다는 점이다. 위 이미지에 나온 검색 결과 중 첫번째 글의 베스트 답변은 컴포저로 버전을 명시해서 설치하라는 것이다.

그럼 이 방법으로 직전 버전인 5.8.26을 설치해보자.

composer create-project laravel/laravel="5.8.26" myProject

5.8.26 버전의 패키지를 찾을 수 없다! 그렇다면 두번째 베스트 답변은 어떨까?

--5.8.26이라는 옵션은 존재하지 않는다며 설치 실패! 두 방법 모두 내가 원하는 버전이 설치 안되는 수준이 아니라 아예 설치 자체가 안된다.

laravel/laravel과 laravel/framework

왜일까? 위의 컴포저 명령문을 다시 한 번 자세히 살펴보면 laravel/laravel 패키지를 설치를 시도한다는걸 알 수 있다. laravel/laravel의 깃헙 저장소에 가서 릴리즈 내역을 보면 최신 버전이 5.8.17이다. 5.8.27은 어디로 간거지?

5.8.17로 설치해보면? 설치된다.

버전을 확인해볼까?

5.8.27!??

이런 현상이 벌어지는 이유는 라라벨의 구조 때문에다. 라라벨은 laravel/laravel과 laravel/framework 패키지를 가지고 있다. laravel/framework가 라라벨 코어 프레임워크이고 laravel/laravel은 laravel/framework를 이용한 뼈대(skeleton) 애플리케이션이다. 즉 laravel/laravel은 일종의 퀵스타트 예제인 셈이다. laravel/laravel과 laravel/framework의 관계는 appkr님의 글에도 잘 정리되어 있으니 참고하자.

laravel/laravel의 composer.json을 살펴보면 다음과 같이 laravel/framework에 의존하는 것을 확인할 수 있다.

"require": {
    "php": "^7.1.3",
    "fideloper/proxy": "^4.0",
    "laravel/framework": "5.8.*",
    "laravel/tinker": "^1.0"
},

“laravel/framework”: “5.8.*” 식으로 의존하기 때문에 5.8의 최신 버전이 설치된다. 따라서 특정 버전의 라라벨을 설치하는 방법은 간단하다. laravel/laravel을 clone 혹은 내려받기한 다음 composer.json에 laravel/framework의 정확한 버전을 지정한 뒤 composer install로 설치하는 것이다.

laravel/laravel clone 혹은 내려받기(설치 아님)

내려받기는 설명할게 없으니 git clone으로 진행해보자.

git clone git@github.com:laravel/laravel.git myProject

laravel/laravel에 기여하려고 클론한 것은 아니니 깃 정보를 제거하자.

cd myProject
rm -rf .git

composer.json을 열고 "laravel/framework": "5.8.*"을 "laravel/framework": "5.8.26" 으로 바꾼다.

"require": {
    "php": "^7.1.3",
    "fideloper/proxy": "^4.0",
    "laravel/framework": "5.8.26",
    "laravel/tinker": "^1.0"
},

컴포저로 의존 패키지들을 설치한다.

composer install

설치가 완료되면 버전을 확인해보자.

php artisan

5.8.26이 설치되었다.

컴포저에 익숙하신 분이라면 별 내용 아닐 수 있는데, 의외로 검색결과에 제대로 된 답변들이 없어서 정리해봤습니다. 필요할 때 도움이 되면 좋겠네요~ 🙂

2019년 7월 4일
1일 1식 라라벨

[1일 1식 라라벨] 모델 변경 이력을 자동으로 저장해주는 패키지 Revisionable

위키백과의 “라라벨” 문서가 수정된 내역

위키의 핵심 기능은 과거의 모든 변경 내역을 조회할 수 있고, 원하면 과거 버전으로 쉽고 되돌아갈 수 있는 것이라 생각한다.
간혹 위키 같이 과거의 변경 내역을 기록으로 남기고 조회하는 기능이 필요할 때가 있다. 내가 운영하는 카페에서는 사물함 관리에 이 기능이 필요했다. 사물함 대여자 정보를 업데이트 할 때 실수를 할 수 있으므로, 변경되기 전의 데이터가 어딘가에 남아있어야 했다. 당시에는 단순하게 똑같은 테이블을 하나 더 만들어서(lockers 테이블과 똑같은 lockers_logs 테이블을 만드는 식으로) 업데이트 전에 백업하는 식으로 구현했다.

이런 기능이 내게만 필요했던 건 아니었는지 크리스 듀엘(Chris Duell)이 Revisionable이라는 패키지를 만들었다. 이 패키지를 사용하면 모델에 변화가 있을때마다 자동으로 ‘누가’, ‘무엇을’, ‘언제’, ‘어떻게’ 수정했는지가 저장된다. 수정내역을 남기고 싶은 모델에 RevisionableTrait 트레이트를 사용한다고 선언하기만 하면 된다. 사물함 관리 기능 만들 때 이 패키지가 알았더라면 ㅠ

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;
use Venturecraft\Revisionable\RevisionableTrait;

class Post extends Model
{
    use RevisionableTrait;
}

실전에서 어떻게 쓰이는지 보는게 가장 와 닿을 것 같다. 내 카페용 애플리케이션에 관심있는 사람들은 없겠지만 겸사겸사 한 번 적용해보겠다.

설치

컴포저로 설치한다.

composer require venturecraft/revisionable

설치가 완료되면 config/app.php 파일의 providers 항목에 RevisionableServiceProvider를 등록한다.

'providers' => [
    Venturecraft\Revisionable\RevisionableServiceProvider::class,
]

설정 파일과 마이그레이션 파일을 퍼블리싱한다.

php artisan vendor:publish --provider="Venturecraft\Revisionable\RevisionableServiceProvider"

// 제대로 진행된다면 아래와 같은 결과 메시지가 터미널에 출력된다.
Copied File [/vendor/venturecraft/revisionable/src/config/revisionable.php] To [/config/revisionable.php]
Copied Directory [/vendor/venturecraft/revisionable/src/migrations] To [/database/migrations]
Publishing complete.

Revisionable 패키지는 모든 모델의 수정내역을 하나의 테이블로 관리한다. 마이그레이션을 실행한다.

php artisan migrate

데이터가 어떻게 저장되는지 확인하기 위해 마이그레이션 파일을 살펴보자.

public function up()
{
    Schema::create('revisions', function ($table) {
        $table->increments('id');
        $table->string('revisionable_type');
        $table->integer('revisionable_id');
        $table->integer('user_id')->nullable();
        $table->string('key');
        $table->text('old_value')->nullable();
        $table->text('new_value')->nullable();
        $table->timestamps();

        $table->index(array('revisionable_id', 'revisionable_type'));
    });
}

revisionable_type은 수정한 모델의 타입이고 revisionable_id는 수정한 모델의 ID 값이다. 이런 방식으로 하나의 테이블에서 모든 모델의 변경사항을 다루는 걸 일대다 다형성 관계라고 한다. 다형성 관계에 익숙하지 않은 사람들은 매뉴얼을 참고하자.

key는 모델의 어떤 값이 변경되었는지를 저장하는 값이다. 예를 들어 Post 모델의 title이 수정되었다면 key에 ‘title’이 값으로 저장된다.

카페용 애플리케이션에서 사물함은 Locker 모델로 관리했다. Locker 모델에 RevisionableTrait를 끼워넣는다.

<?php

namespace App;

use Carbon\Carbon;
use Illuminate\Database\Eloquent\Model;
use Venturecraft\Revisionable\RevisionableTrait;

class Locker extends Model
{
    use RevisionableTrait;

    ...이하 생략

Locker를 업데이트하는 LockerService::update()는 원래 아래와 같았다.

class LockerService
{
    public function update($request, $locker)
    {
        DB::transaction(function () use ($request, $locker) {
            $this->backup($locker);

            $inputs = $this->buildInputsForUpdate($request, $locker);

            $locker->update($inputs);
        });
    }

코드는 간단하다. 백업하고 업데이트할 데이터를 준비해서 업데이트한다.

이제 Revisionable이 수정내역을 관리해주기 때문에 백업하는 코드는 더이상 필요 없다. 그래서 $this->backup($locker); 줄을 지우고 LockerService::backup() 메소드를 통째로 제거했다.

테스트로 데이터를 하나 변경해봤다. 홍길동이 대여하고 있던 사물함을 장길산이 사용하게 된 시나리오다.

‘사용자’, ‘이용 시작 시점’, ‘이용 종료 시점’, ‘비밀번호’가 바뀌었다. revisions 테이블을 보면 아래와 같이 4개의 데이터가 추가되었다. 

변경 행위는 한 번인데, 변경된 필드마다 데이터가 하나씩 생성되는 점은 조금 아쉽다. 현재로서는 같은 행동이 원인이 되어 바뀌었는지 여부를 판단할 수 있는 유일한 방법은 revisions 테이블의 created_at 이 같은지 확인하는 방법 뿐이다. 수정내역을 사용자의 행동 단위로 묶을 수 있도록 식별값을 하나 더 추가했으면 어땟을까 싶다.

기본적인 기능 외에 아래와 같이 다양한 옵션을 제공한다. 필요할 때 패키지의 매뉴얼을 보고 활용하자.

  • 변경 뿐만 아니라 생성 기록도 저장하기
  • 저장할 필드, 혹은 제외할 필드 지정하기
  • 수정내역 저장 비활성화
  • 수정내역 최대 저장 갯수 지정
  • 출력 형식 변경하기

이 글은 7월 2일자 1일 1식 라라벨에 발행된 글입니다. 8월호 구독자를 모집하고 있습니다. 월 1만원으로 최신 라라벨 소식을 받아보세요.

[1일 1식 라라벨] 2019년 8월호 구독자 모집

1일 1식 라라벨 8월호 구독자를 모집합니다.

7월호 3주차가 끝났는데 다행히 펑크를 낸 날은 없었네요 🙂 용기내서 조금 더 해봅니다.

7월호에 발행했던 글들은 아래와 같습니다.

  • 5.8.25 버전부터 Response::assertViewHas()로 공유 데이터도 확인 가능
  • 모델 변경 이력을 자동을 저장해주는 패키지 Revisionable
  • 5.8.27 버전에 whereHasMorph() 추가됨
  • 특정 버전의 라라벨 설치하기
  • 라라벨 패키지를 선택할 때 물어야 할 8가지 질문
  • 테일러 오트웰은 왜 API 라우트를 routes/web.php에 작성했을까?
  • 테일러 오트웰이 사랑한 헬퍼, tap()
  • 5.8.28 새기능 1 – TestResponse에 tap 기능 추가
  • 5.8.28 새기능 2 – 컬렉션에 병합, 교체 기능 추가
  • 5.8.28 새기능 3 – Session에 only 메소드 추가
  • ERD를 그려주는 Laravel ER Diagram Generator
  • 의존성 충돌 해결하기
  • 라라벨 5.8.29 릴리즈
  • 라라벨 리퀘스트 라이프사이클
  • 라라벨에서 TailwindCSS 사용하기

많은 신청 바랍니다~ 신청 링크 https://forms.gle/ysHkKGdhhKka2ECK8

[1일 1식 라라벨 샘플] route:list를 JSON으로 출력하는 기능이 추가되었다

라라벨 5.8.25가 나왔다. (같은 날 긴급 패치가 나와서 현재 최신 버전은 5.8.26이다.) 5.8.25에서는 route:list를 JSON으로 출력하는 기능이 추가되었다.

route:list

route:list는 터미널에서 전체 라우트를 테이블 형태로 출력하는 아티즌 명령어이다. 아래와 같이 실행할 수 있다.

php artisan route:list

아래는 모던 PHP 유저 그룹 홈페이지 의 라우트를 출력한 예시이다.

route:list를 JSON으로 출력하기

라우트 목록을 JSON으로 출력하고 싶으면 --json 옵션을 붙이면 된다.

php artisan route:list --json

그러면 아래와 같이 JSON 형식으로 출력된다.

왜 만들었을까?

이 기능을 추가한 제이슨 맥크레리“프로그램으로 쉽게 파싱될 수 있어서 다른 도구나 서비스에 의해 쓰이기 좋다”고 이유를 밝혔다. 그런데 다른 도구나 서비스가 아티즌 커맨드를 쓰는 일이 있나 싶다.

기존에도 원한다면 라우트 파사드를 통해 이용해서 전체 라우트를 조회할 수 있었다.

$routes = \Illuminate\Support\Facades\Route::getRoutes()->get();

// get() 메소드에 조회하고자 하는 HTTP 메소드를 지정할 수도 있다.
$getRoutes = \Illuminate\Support\Facades\Route::getRoutes()->get('GET');

굳이 추가로 만든 이유를 찾자면 몇가지 항목으로 미리 정리해서 뽑아주기 때문에 살짝 더 편리할 수 있다 정도 아닐까? 아티즌 커맨드로 라우트 목록을 받으려면 아래와 같이 하면 된다.

Artisan::call('route:list --json');
$routes = Artisan::output();

어디에 쓰지?

전 직장에 입사했을 때, 이미 라라벨로 만든 애플리케이션이 잘 돌아가고 있었다. 다만, 테스트가 하나도 없었다. 사장님이 우선은 접속 안되는 페이지가 없는지 확인하는 테스트만 있어도 좀 안심이 될 것 같다고 이야기했고 나도 동의했다. 그때는 라우트 목록을 JSON으로 뽑는 기능도 없었고, 라우트 파사드로 조회할 수 있는지도 몰라서 아래와 같이 단순 무식하게 짰다.

$this->get("/")->assertSuccessful();

$this->get("/user/login")->assertSuccessful();
$this->get("/user/add")->assertSuccessful();
$this->get("/user/forget")->assertSuccessful();
... //이렇게 수십 줄이 이어진다.

// 로그인이 필요한 페이지는 이런 식으로
$this->actingAs($user)->get('/user/changePassword')->assertSuccessful();

지금 다시 짠다면 요번에 추가된 기능이나 라우트 파사드를 이용해서 좀 더 프로그램 답게(programmatically) 작성할 수 있지 않을까 싶다. GET 메소드만 쌱 조회해서 미들웨어에 auth 있나 없나 보고 그에 따라 샤샥.

이 글은 하루에 한 편씩 라라벨 관련 글을 메일로 보내드리는 [1일 1식 라라벨] 의 샘플 원고입니다. 조금 더 길어질 수도 짧아질 수도 있습니다만, 어느 정도 공들여 쓴 블로그 포스트 정도라고 생각해주시면 될 것 같습니다. 7월호 유료구독자를 모집하고 있습니다.

[1일 1식 라라벨] 구독자 모집

안녕하세요. 이현석입니다. 저는 PHP를 주로 사용하는 개발자이고 개발 관련 책과 글도 씁니다. 출간한 책으로는 “바쁜 팀장님 대신 알려주는 신입 PHP 개발자 안내서“가 있습니다. 대외활동으로는 모던 PHP 유저 그룹에서 꾸준히 활동 중이고, 코딩 야학에도 조력자로 참여하고 있습니다. 라라벨 관련해서는 XE 기술 세미나와 XECON에서 발표한 바 있고, 패스트캠퍼스에서 강의한 바 있습니다.

일간 이슬아와 이다님의 매일마감을 보고 용기내서 유료 뉴스레터를 시작합니다. 라라벨을 4 시절부터 써오고 있는데, 라라벨의 인기와 영향력은 날이 갈수록 늘어서 해외에서는 매일 새로운 자료들이 쏟아져 나오고 있습니다. 일 안하고 하루종일 읽기만 해도 과연 다 소화할 수 있을까 의문이 들 정도입니다. 한편, 한글로 된 자료는 좀처럼 찾아보기가 쉽지 않습니다. 그래서 매일 열심히 새로 나오는 라라벨 관련 정보들을 익히고, 하루에 한 편씩 알기 쉽게 정리해서 메일로 보내주는 일을 해보고자 합니다. 뉴스 큐레이션은 아닙니다. 샘플 원고는 여기서 확인하실 수 있습니다.

구독료는 한 달 1만원 입니다. 6월 말일까지 신청받고, 7월 1일부터 시작해서 7월 말일 까지 주중에 한 편씩 글을 보내드립니다. 주말엔 쉽니다.

보내드리는 글은 시간이 지나면 모든 사람들에게 공개할 예정입니다. 마음이 바뀌어 공개를 안할 수도 있습니다만, 일단은 3주 정도 후에 공개할까 합니다.

제 자신은 많은 개발자들이 무료로 공개한 자료로 학습했으면서, 글을 유료로 판매하는 것에 대해 다소 죄스런 마음이 있습니다. 하지만 앞서 말씀드렸듯 한글로 된 자료가 매우 희박한데, 그 이유는 지식을 공유할 만큼 여유로운 개발자의 수가 충분히 많지 않아서라고 생각합니다. 그래서 누군가는 여가시간이 아닌 일과시간을 이용해서 자료를 만들고 그것으로 돈을 버는 것도 의미가 있다고 믿습니다.

한 분 이라도 신청해주시면 진행합니다. 단 한 분만 구독하시더라도 최선을 다하겠습니다.

신청하시는 곳 https://forms.gle/rB4jFH6CYDETqpR97

라라벨에서 테이블 변경 마이그레이션 추가 후 테스트가 깨졌다

개발 단계에서는 테이블 생성하는 마이그레이션을 고쳐가며 작업해도 괜찮습니다. 하지만 이미 애플리케이션을 배포한 뒤라면 그럴 수 없죠. 기존 테이블을 수정하는 마이그레이션을 작성해야 합니다.

오늘은 기존 테이블을 변하는 마이그레이션을 작성하다가 겪은 일을 공유하고자 합니다.

아래와 같이 아주 간단한 마이그레이션을 작성했습니다.

public function up()
{
    Schema::table('posts', function(Blueprint $table) {
       $table->renameColumn('movie_id', 'postable_id');
       $table->string('postable_type')->default('');
    });
}

posts 테이블에서 movie_id 컬럼명을 postable_id로 바꾸고, postable_type 컬럼을 하나 추가하는 것입니다.

개발 환경에서는 마이그레이션이 문제 없이 실행되었는데, 테스트를 돌려보니 에러가 납니다. 에러 메시지를 보니 postable_type 컬럼이 없다고 합니다.

table posts has no column named postable_type

분명히 개발 환경에서 마이그레이션할 때 문제가 없었는데 어떻게 된 일일까요?

문제는 SQLite 때문이었습니다. 저는 테스트 속도를 높이기 위해 테스트시에는 SQLite를 쓰고 있습니다. 근데, SQLite는 테이블을 수정할 때 한 번에 여러 컬럼을 추가할 수가 없다고 하네요. 그래서 테스트 환경에서는 두번째 작업인 postable_type 컬럼 추가가 진행이 안된 것입니다.

해결 방법은 간단합니다. 수정하는 마이그레이션인 경우 한 번에 하나씩만 바꾸도록 코드를 바꿔주면 됩니다.

 public function up()
{
    Schema::table('posts', function(Blueprint $table) {
       $table->renameColumn('movie_id', 'postable_id');
    });

    Schema::table('posts', function(Blueprint $table) {
        $table->string('postable_type')->default('');
    });
}

물론 테스트 할 때 SQLite 안쓰시는 분은 신경쓰지 않으셔도 됩니다.

라라벨 5.8.16 새기능(2)

라라벨 5.8.16에서는 이전에 소개한 마이그레이션 이벤트 이외에 두가지 기능이 더 추가 되었습니다.

하나는 PostgreSQL을 사용하는 사람을 위한 기능으로, migrate:fresh 할 때 type을 지울 수 있는 옵션이 추가된 것입니다. 개발자에 의하면 PostgreSQL 에서는 ENUM에 타입을 사용하는데 migrate:fresh를 하면 테이블은 다 지워지지만 이 타입이 남아서 문제가 생겼었다고 하네요. 데이터베이스 뷰를 지우는 옵션을 사용하는 것과 같은 방법으로 사용하면 된다고 합니다. (데이터베이스 뷰를 지우는 옵션도 있었군요…ㅎㅎ)

php artisan migrate:fresh --drop-types

다른 하나는 MailMessage 클래스에 Renderable 컨트랙트를 추가한 것입니다. 이를 통해 알림(Notification) 메일이 어떻게 보내질 것인지 브라우저로 확인해볼 수 있다고 하네요. 예를 들어, 컨트롤러에서 다음과 같이 하면 된다고 합니다.

return (new FooNotification())->toMail('example@example.com');

브라우저로 메일 내용을 미리보는 건 Mailable 클래스에 이미 있던 기능인데, 같은 기능을 알림 메일에 사용하는 MailMessage 클래스에도 추가했다고 합니다.

그렇지 않아도 이번에 막 알림을 메일로도 받을 수 있게 작업하려는 참이었는데 잘됐네요 ㅎㅎ