Laravel 로 웹싸이트 개발하기 #2

devil
Standard

Stapler 패키지의 설명 내용과는 다르게, 여기서는 1-to-1 관계인 User 와 Avatar 를 사용하지 않고, 1-to-many 관계인 User 와 Picture 모델을 정의하여 사용한다. 현재 작업중인 프로젝트의 기술 명세서를 보면 접속한 회원이 다수의 사진을 자유롭게 올릴 수 있어야 한다. Jeffrey Way 의 Generator 를 이용하여 다음과 같이 Picture 모델의 마이그레이션을 생성한다.

php artisan generate:migration create_pictures_table --fields="user_id:integer, title:string:nullable, image_file_name:string, image_file_size:integer, image_content_type:string, image_updated_at:timestamp"

마이그레이션을 하면 DB 는 설정이 되었고, Picture 모델의 정의는 아래와 같이 했다.

<?php namespace Teeshot\Users;

use Codesleeve\Stapler\ORM\StaplerableInterface;
use Codesleeve\Stapler\ORM\EloquentTrait;
use Eloquent;

class Picture extends Eloquent implements StaplerableInterface {

    use EloquentTrait;

    protected $table = 'pictures';
    public $timestamps = true;
    protected $fillable = [ 'image' ];

    /**
     * Constructor
     */
    public function __construct(array $attributes = array()) {
        $this->hasAttachedFile('image', [
            'styles' => [
                'medium' => '320x320#',
                'thumb' => '100x100#'
            ]
        ]);

        parent::__construct($attributes);
    }

    public function user()
    {
        return $this->belongsTo('User');
    }
}

궁극적으론, 뷰에서 아래와 같은 형태의 접근이 가능한 시나리오다.

{{ $user->pictures[index]->image->url() }}
{{ $user->pictures[index]->image->url('thumb') }}

뷰 역시 추가되는 부분이 필요한데, DB 에 이미 기록된 이미지 파일들을 출력하기 위한 내용이다.

<div class="image-list">
    @if (count($pictures) > 0)
        @foreach ($pictures->chunk(4) as $pictureSet)
            <div class="row pictures">
                @foreach ($pictureSet as $picture)
                    <div class="col-sm-3 col-md-3 user-block">
                        <a class="btn btn-danger btn-small" href="#" rel="" rev="{{$picture->id}}"><span class="glyphicon glyphicon-remove" aria-hidden="true"></span></a>
                        <img src="{{ $picture->image->url('thumb') }}" />
                    </div>
                @endforeach
            </div>
        @endforeach
    @else
        <div class="row pictures"></div>
    @endif
</div>
<hr />

해당 뷰 하단에 JavaScript 함수도 아래와 같이 추가 변경한다.

$('#uploader').fileapi({
    url: '{{ route("users.upload") }}',
    accept: 'image/*',
    autoUpload: true,
    multiple: true,
    maxFiles: 5,
    maxSize: 6 * FileAPI.MB,
    imageTransform: { // resize by max side
        maxWidth: 800,
        maxHeight: 600
    },
    elements: {
        empty: { show: '.b-upload__hint' },
        list: '.js-files',
        file: {
            tpl: '.js-file-tpl',
            preview: { el: '.b-thumb__preview', width: 64, height: 64 },
            upload: { show: '.progress' },
            complete: { hide: '.progress' },
            progress: '.js-progress'
        }
    },
    onFileComplete: function (evt, uiEvt){
        var json = uiEvt.result;
        var element = '<div class="col-md-3 user-block"><img src="'+json.name+'"></div>';
        var lastDiv = $(".image-list > div:last");
        var count = lastDiv.children().length;

        if (count < 4) {
            lastDiv.append(element);
        } else {
            var newDiv = $('<div class="row pictures">');
            $(".image-list").append(newDiv);
            newDiv.append(element);
        }
        evt.widget.remove(uiEvt.file);
    }
});

이제 마지막으로 콘트롤러 UsersController 의 upload() 메서드를 다음과 같이 변경하고, 뷰에 필요한 객체 콜렉션을 넘겨줄 edit() 메서드도 추가한다.

public function upload()
{
    $file = Input::file('filedata');

    $picture = new Picture();
    $picture->image = $file;
    $picture->user_id = Auth::user()->id;
    $picture->save();

    return Response::json(['name' => $picture->image->url('thumb')], 200);

}

public function edit()
{
    $user = Auth::user();
    $pictures = $user->pictures()->get();
    return View::make('users.edit', compact('pictures'));
}

지금까지의 작업만으로 프론트앤드를 위한 FileAPI JQuery 라이브러리와 백앤드를 위한 Stapler 패키지가 조합되어 제법 쓸만한 파일 업로드 기능이 동작하게 된다. 이제 /app/config/packages/codesleeve/laravel-stapler 디렉토리에서 stapler.php 파일을 열어서, Stapler 의 스토리지 드라이버를 ‘storage’ => ‘filesystem’ 에서 ‘storage’ => ‘s3’ 로 바꾸면, 그 이후부터의 모든 업로드는 S3로 업로드 된다. 지금까지 구현된 내용의 스크린샷은 아래와 같다.

As simple as that.