11 changed files with 263 additions and 4 deletions
-
20app/Entities/Projects/File.php
-
5app/Entities/Projects/Project.php
-
77app/Http/Controllers/Projects/FilesController.php
-
37database/migrations/2017_08_03_235706_create_files_table.php
-
6resources/views/projects/features-export-html.blade.php
-
58resources/views/projects/files.blade.php
-
3resources/views/projects/partials/nav-tabs.blade.php
-
7routes/web/projects.php
-
38tests/Feature/Projects/UploadFilesTest.php
-
8tests/TestCase.php
-
8tests/Unit/Models/ProjectTest.php
@ -0,0 +1,20 @@ |
|||||
|
<?php |
||||
|
|
||||
|
namespace App\Entities\Projects; |
||||
|
|
||||
|
use Illuminate\Database\Eloquent\Model; |
||||
|
|
||||
|
class File extends Model |
||||
|
{ |
||||
|
protected $fillable = ['fileable_id', 'fileable_type', 'type_id', 'filename', 'title', 'description']; |
||||
|
|
||||
|
public function fileable() |
||||
|
{ |
||||
|
return $this->morphTo(); |
||||
|
} |
||||
|
|
||||
|
public function project() |
||||
|
{ |
||||
|
return $this->morphTo('fileable', Project::class); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,77 @@ |
|||||
|
<?php |
||||
|
|
||||
|
namespace App\Http\Controllers\Projects; |
||||
|
|
||||
|
use App\Entities\Projects\File; |
||||
|
use App\Http\Controllers\Controller; |
||||
|
use Illuminate\Database\Eloquent\Model; |
||||
|
use Illuminate\Http\Request; |
||||
|
|
||||
|
class FilesController extends Controller |
||||
|
{ |
||||
|
private $fileableTypes = [ |
||||
|
'projects' => 'App\Entities\Projects\Project', |
||||
|
]; |
||||
|
|
||||
|
public function index(Request $request, $fileableId) |
||||
|
{ |
||||
|
$fileableType = $request->segment(1); // projects, features
|
||||
|
$modelName = $this->getModelName($fileableType); |
||||
|
$modelShortName = $this->getModelShortName($modelName); |
||||
|
$model = $modelName::findOrFail($fileableId); |
||||
|
$files = $model->files; |
||||
|
|
||||
|
return view($fileableType.'.files', [$modelShortName => $model, 'files' => $files]); |
||||
|
} |
||||
|
|
||||
|
public function create(Request $request, $fileableId) |
||||
|
{ |
||||
|
$fileableExist = array_search($request->get('fileable_type'), $this->fileableTypes); |
||||
|
|
||||
|
if ($fileableExist) { |
||||
|
$file = $this->proccessPhotoUpload($request->except('_token'), $request->get('fileable_type'), $fileableId); |
||||
|
|
||||
|
if ($file->exists) |
||||
|
flash()->success('Upload file berhasil.'); |
||||
|
else |
||||
|
flash()->error('Upload file gagal, coba kembali.'); |
||||
|
} else |
||||
|
flash()->error('Upload file gagal, coba kembali.'); |
||||
|
|
||||
|
return back(); |
||||
|
} |
||||
|
|
||||
|
private function proccessPhotoUpload($data, $fileableType, $fileableId) |
||||
|
{ |
||||
|
// dd(get_class_methods($data['files']));
|
||||
|
$file = $data['files']; |
||||
|
// $fileName = md5(uniqid(rand(), true)).'.'.$file->getClientOriginalExtension();
|
||||
|
$fileName = $file->hashName(); |
||||
|
// dd($fileName);
|
||||
|
|
||||
|
$fileData['fileable_id'] = $fileableId; |
||||
|
$fileData['fileable_type'] = $fileableType; |
||||
|
$fileData['filename'] = $fileName; |
||||
|
$fileData['title'] = $data['title']; |
||||
|
$fileData['description'] = $data['description']; |
||||
|
\DB::beginTransaction(); |
||||
|
// dd(is_dir(storage_path('app/public/files')));
|
||||
|
$file->storeAs('public/files', $fileName); |
||||
|
// $file->move(storage_path('app/public/files'));
|
||||
|
$file = File::create($fileData); |
||||
|
\DB::commit(); |
||||
|
|
||||
|
return $file; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
public function getModelName($fileableType) |
||||
|
{ |
||||
|
return isset($this->fileableTypes[$fileableType]) ? $this->fileableTypes[$fileableType] : false; |
||||
|
} |
||||
|
|
||||
|
public function getModelShortName($modelName) |
||||
|
{ |
||||
|
return strtolower((new \ReflectionClass($modelName))->getShortName()); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,37 @@ |
|||||
|
<?php |
||||
|
|
||||
|
use Illuminate\Support\Facades\Schema; |
||||
|
use Illuminate\Database\Schema\Blueprint; |
||||
|
use Illuminate\Database\Migrations\Migration; |
||||
|
|
||||
|
class CreateFilesTable extends Migration |
||||
|
{ |
||||
|
/** |
||||
|
* Run the migrations. |
||||
|
* |
||||
|
* @return void |
||||
|
*/ |
||||
|
public function up() |
||||
|
{ |
||||
|
Schema::create('files', function (Blueprint $table) { |
||||
|
$table->increments('id'); |
||||
|
$table->unsignedInteger('fileable_id'); |
||||
|
$table->string('fileable_type', 60); |
||||
|
$table->tinyInteger('type_id')->unsigned()->nullable(); |
||||
|
$table->string('filename', 60); |
||||
|
$table->string('title', 60); |
||||
|
$table->string('description')->nullable(); |
||||
|
$table->timestamps(); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Reverse the migrations. |
||||
|
* |
||||
|
* @return void |
||||
|
*/ |
||||
|
public function down() |
||||
|
{ |
||||
|
Schema::dropIfExists('files'); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,58 @@ |
|||||
|
@extends('layouts.app') |
||||
|
|
||||
|
@section('title', trans('project.files') . ' | ' . $project->name) |
||||
|
|
||||
|
@section('content') |
||||
|
@include('projects.partials.breadcrumb',['title' => trans('project.files')]) |
||||
|
|
||||
|
<h1 class="page-header"> |
||||
|
{{ $project->name }} <small>{{ trans('project.files') }}</small> |
||||
|
</h1> |
||||
|
|
||||
|
@include('projects.partials.nav-tabs') |
||||
|
<div class="row"> |
||||
|
<div class="col-md-8"> |
||||
|
<div class="panel panel-default table-responsive"> |
||||
|
<div class="panel-heading"> |
||||
|
<h3 class="panel-title">{{ trans('project.files') }}</h3> |
||||
|
</div> |
||||
|
<table class="table table-condensed table-striped"> |
||||
|
<thead> |
||||
|
<th>{{ trans('app.table_no') }}</th> |
||||
|
<th>{{ trans('file.title') }}</th> |
||||
|
<th class="text-center">{{ trans('file.description') }}</th> |
||||
|
<th class="text-center">{{ trans('app.action') }}</th> |
||||
|
</thead> |
||||
|
<tbody class="sort-files"> |
||||
|
@forelse($files as $key => $file) |
||||
|
<tr id="{{ $file->id }}"> |
||||
|
<td>{{ 1 + $key }}</td> |
||||
|
<td>{{ $file->title }}</td> |
||||
|
<td>{{ $file->description }}</td> |
||||
|
<td class="text-center"></td> |
||||
|
</tr> |
||||
|
@empty |
||||
|
<tr><td colspan="4">{{ trans('file.empty') }}</td></tr> |
||||
|
@endforelse |
||||
|
</tbody> |
||||
|
</table> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div class="col-md-4"> |
||||
|
<div class="panel panel-default"> |
||||
|
<div class="panel-heading"><h3 class="panel-title">Upload new File</h3></div> |
||||
|
<div class="panel-body"> |
||||
|
{!! Form::open(['route' => ['files.upload', $project->id], 'id' => 'upload-files', 'files' => true]) !!} |
||||
|
{{ Form::hidden('fileable_type', get_class($project)) }} |
||||
|
{!! FormField::file('files', ['label' => 'Upload File', 'placeholder' => 'Pilih File']) !!} |
||||
|
{!! FormField::text('title') !!} |
||||
|
{!! FormField::textarea('description') !!} |
||||
|
{!! Form::submit(trans('app.upload_files'), ['class' => 'btn btn-info']) !!} |
||||
|
{!! Form::close() !!} |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
|
||||
|
|
||||
|
@endsection |
||||
@ -0,0 +1,38 @@ |
|||||
|
<?php |
||||
|
|
||||
|
namespace Tests\Feature\Projects; |
||||
|
|
||||
|
use App\Entities\Projects\Project; |
||||
|
use Tests\TestCase; |
||||
|
|
||||
|
class UploadFilesTest extends TestCase |
||||
|
{ |
||||
|
/** @test */ |
||||
|
public function user_can_upload_document_to_a_project() |
||||
|
{ |
||||
|
$user = $this->adminUserSigningIn(); |
||||
|
$project = factory(Project::class)->create(['owner_id' => $user->id]); |
||||
|
$this->visit(route('projects.files', $project->id)); |
||||
|
$this->seeElement('form', ['id' => 'upload-files']); |
||||
|
$this->seeElement('input', ['id' => 'files']); |
||||
|
$this->seeElement('input', ['type' => 'submit', 'value' => trans('app.upload_files')]); |
||||
|
|
||||
|
$this->attach(storage_path('app/guitar-640.jpg'), 'files'); |
||||
|
$this->type('Judul file', 'title'); |
||||
|
$this->type('Deskripsi file yang diuplod.', 'description'); |
||||
|
$this->press(trans('app.upload_files')); |
||||
|
|
||||
|
$this->assertCount(1, $project->files); |
||||
|
|
||||
|
$this->seeInDatabase('files', [ |
||||
|
'fileable_id' => $project->id, |
||||
|
'fileable_type' => 'App\Entities\Projects\Project', |
||||
|
'title' => 'Judul file', |
||||
|
'description' => 'Deskripsi file yang diuplod.', |
||||
|
]); |
||||
|
|
||||
|
$file = $project->files->first(); |
||||
|
$filePath = storage_path('app/public/files/' . $file->filename); |
||||
|
$this->assertFileExistsThenDelete($filePath, 'File doesn\'t exists.'); |
||||
|
} |
||||
|
} |
||||
Write
Preview
Loading…
Cancel
Save
Reference in new issue