How to associate files to post with Laravel 5.6 - php

I am using Laravel for my web app and I want to associate files to my posts in indepent way with his own form, but I have some problems
My routes (I am using a auth control package, but actually I am admin):
Route::post('file', 'fileController#store')->name('file.store')
->middleware('permission:file.create');
Route::get('file', 'fileController#index')->name('file.index')
->middleware('permission:file.index');
Route::get('file/create/', 'fileController#create')->name('file.create')
->middleware('permission:file.create');
Route::put('file/{id}', 'fileController#update')->name('file.update')
->middleware('permission:file.edit');
Route::get('file/{id}', 'fileController#show')->name('file.show')
->middleware('permission:file.show');
Route::delete('file/{id}', 'fileController#destroy')->name('file.destroy')
->middleware('permission:file.destroy');
Route::get('file/{id}/edit', 'fileController#edit')->name('file.edit')
->middleware('permission:file.edit');
Route::get('download/{filename}', 'fileController#download')->name('file.download')
->middleware('permission:file.download');
My migration:
Schema::create('files', function (Blueprint $table) {
$table->increments('id');
$table->integer('user_id')->unsigned();
$table->integer('files_id')->unsigned();
$table->string('filenames');
$table->integer('fileable_id')->unsigned();
$table->string('fileable_type');
$table->timestamps();
});
My File Model:
class File extends Model
{
protected $fillable = [
'filenames', 'project_id'
];
public function user()
{
return $this->belongsTo(User::class);
}
My Project Model:
public function files()
{
return $this->morphMany(File::class, 'fileable')->whereNull('files_id');
}
My Controller to store:
class FileController extends Controller
{
public function store(Request $request)
{
$this->validate($request, [
'filenames' => 'required',
'project_id' => 'required',
// 'filenames.*' => 'mimes:doc,pdf,docx,zip'
]);
if($request->hasfile('filenames'))
{
foreach($request->file('filenames') as $file)
{
$name=$file->getClientOriginalName();
$file->move(public_path().'/files/', $name);
$data[] = $name;
}
}
$file= new File();
$file->filenames = $request->get('filenames');
$file->filenames= $name;
$file->user()->associate($request->user());
$project = Project::findOrFail($request->get('project_id'));
$project->files()->save($file);
$file->save();
return back();
}
public function download( $filename = '' ) {
// Check if file exists in storage directory
$file_path = public_path() . '/files/' . $filename;
if ( file_exists( $file_path ) ) {
// Send Download
return \Response::download( $file_path, $filename );
} else {
return back()->with('info', 'Archivo no existe en el servidor');
}
}
The Form in blade:
<form method="post" action="{{ route('file.store') }}" enctype="multipart/form-data">
<div class="input-group hdtuto control-group lst increment" >
<input type="file" name="filenames[]" class="myfrm form-control">
<input type="hidden" name="project_id" value="{{ $project->id }}" />
<div class="input-group-btn">
<button class="btn btn-success" type="button"><i class="fldemo glyphicon glyphicon-plus"></i>Add</button>
</div>
</div>
<button type="submit" class="btn btn-success" style="margin-top:10px">Submit</button>
</form>
Foreach to download files:
#foreach($project->files as $file)
<li>{{ $file->user->name }}: <a href="{{ url('/download/')}}/{{$file->filenames}}" download> {{$file->filenames}}</a></li>
#endforeach
I send files from Project Controll

The reason you are getting the first error message is because the Project with the id you get from Request is not found in the Database and returns null instead of an object. That would mean you are indeed calling files() method on null. To resolve this there are multiple steps.
1.) Make sure project_id is inside the Request at all times:
$this->validate($request, [
'filenames' => 'required',
'project_id' => 'required',
// 'filenames.*' => 'mimes:doc,pdf,docx,zip'
]);
2.) Make sure to check for project if it exists after retrieving it from database, this can be done in two ways.
a) You can either find the project or throw an Exception if it's not found:
$project = Project::findOrFail($request->get('project_id');`
b) You can check with a simple if statement if it does not exist and do something
$project = Project::find($request->get('project_id');
if (!$project) {
// Project not found in database
// Handle it
}

Related

How do I show a dynamic navigation bar on a dynamic web page in Laravel?

I have a dynamic navigation bar, created however it won't show on the dynamic web page.
The current output is:
ErrorException
Undefined variable: navContent (View: C:\Users\Computer
Angel\Documents\blog\resources\views\page\dynamic.blade.php)
The desired output is my dynamic.blade.php where the pageContent is the dynamic page content the user inputted through a form and the dynamic navigation bar in the tags.
This is my dynamic.blade.php:
<nav>
#foreach($navContent as $nav)
{!!nav-navName!!}
#endforeach
</nav>
<body>
{!!$pageContent->pageContent!!}
</body>
This is my NavController.php:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Nav;
use DB;
use Illuminate\Database\MySqlConnection;
class NavController extends Controller
{
public function index()
{
$navs = Nav::all();
return view('navManagement', compact('navs'));
}
public function create()
{
return view('createNav');
}
public function store(Request $request)
{
$data = request()->validate([
'navName' => 'required',
'navLink' => 'required',
]);
$nav = new Nav([
'navName' => $request->get('navName'),
'navLink' => $request->get('navLink'),
]);
$nav->save();
return redirect('/n');
}
public function show($navName)
{
$navContent = DB::table('navs')->where('navName',$navName)->first();
return view('page.dynamic', ['navContent' => $navContent]);
}
public function edit($navName)
{
$navContent = DB::table('navs')->where('navName',$navName)->first();
return view('editNav', ['navContent' => $navContent]);
}
public function update(Request $request)
{
$data = $request->validate([
'navName' => 'required|exists:navs,navName',
'navLink' => 'required'
]);
$obj = \App\Nav::where('navName', $request->navName)
->update([
'navLink' => $request->navLink
]);
return redirect('/n');
}
public function destroy(Request $request)
{
$obj = \App\Nav::where('navName', $request->navName)
->delete();
return redirect('/n');
}
}
This is my PageController.php:
<?php
namespace App\Http\Controllers;
use App\Page;
use Illuminate\Http\Request;
use DB;
use Illuminate\Database\MySqlConnection;
class PageController extends Controller
{
public function index()
{
$pages = Page::all();
return view('pageManagement', compact('pages'));
}
public function create()
{
//This will load create.blade.php
return view('createPage');
}
public function store(Request $request)
{
$data = request()->validate([
'title' => 'required',
'URI' => 'required|min:5|max:10|',
'pageContent' => 'required',
]);
$page = new Page([
'title' => $request->get('title'),
'URI' => $request->get('URI'),
'pageContent' => $request->get('pageContent'),
]);
$page->save();
return redirect('/p');
}
public function show($URI)
{
$pageContent = DB::table('pages')->where('URI',$URI)->first();
return view('page.dynamic', ['pageContent' => $pageContent]);
}
public function edit($URI)
{
$pageContent = DB::table('pages')->where('URI',$URI)->first();
return view('editPage', ['pageContent' => $pageContent]);
}
public function update(Request $request)
{
$data = $request->validate([
'title' => 'required',
'URI' => 'required|min:5|max:10|exists:pages,URI',
'pageContent' => 'required'
]);
$obj = \App\Page::where('URI', $request->URI)
->update([
'title' => $request->title,
'pageContent' => $request->pageContent
]);
return redirect('/p');
}
public function destroy(Request $request)
{
$obj = \App\Page::where('URI', $request->URI)
->delete();
return redirect('/p');
}
}
This is my Nav.php:
class Nav extends Model
{
protected $fillable = ['navName', 'navLink'];
}
This is my Page.php:
class Page extends Model
{
protected $fillable = ['title', 'URI', 'pageContent'];
}
This is my migration for pages:
public function up()
{
Schema::create('pages', function (Blueprint $table) {
$table->id();
$table->string('title');
$table->string('URI');
$table->text('pageContent');
$table->timestamps();
});
}
This is my migration for nav:
public function up()
{
Schema::create('navs', function (Blueprint $table) {
$table->id();
$table->string('navName');
$table->string('navLink');
$table->timestamps();
});
}
This is my createNav.blade.php:
<form action="/storeNav" method="post">
#csrf
<label for="navName">Navigation Bar Option Name:</label><br>
<input type="text" id="navName" name="navName" autocomplete="off" value="{{ old('navName') }}">
<br>
#error('navName') <p style="color: red">{{ $message }}</p> #enderror
<label for="navLink">Navigation Bar Option Link:</label><br>
<input type="text" id="navLink" name="navLink" autocomplete="off" value="{{ old('navLink') }}">
<br>
#error('navLink') <p style="color: red">{{ $message }}</p> #enderror
<input type="submit" value="Submit">
</form>
This is my createPage.blade.php:
<form action="/storePage" method="post">
#csrf
<label for="title">Title:</label><br>
<input type="text" id="title" name="title" autocomplete="off" value="{{ old('title') }}"><br>
#error('title') <p style="color: red">{{ $message }}</p> #enderror
<label for="URI">URI:</label><br>
<input type="text" id="URI" name="URI" autocomplete="off" value="{{ old('URI') }}"><br>
#error('URI') <p style="color: red">{{ $message }}</p> #enderror
<label for="pageContent">Page Content:</label><br>
<textarea id="pageContent" name="pageContent" value="{{ old('pageContent') }}"></textarea>
#error('pageContent') <p style="color: red">{{ $message }}</p> #enderror
<input type="submit" value="Submit">
</form>
This is my web.php:
Route::get('/page/{URI}', 'PageController#show');
Route::get('/page/{URI}/edit', 'PageController#edit');
Route::get('/p', 'PageController#index');
Route::get('/createPage', 'PageController#create');
Route::post('/storePage', 'PageController#store');
Route::patch('/page/{URI}', 'PageController#update');
Route::delete('/page/{URI}', 'PageController#destroy');
Route::get('/nav/{navName}/edit', 'NavController#edit');
Route::get('/n', 'NavController#index');
Route::get('/createNav', 'NavController#create');
Route::post('/storeNav', 'NavController#store');
Route::patch('/nav/{navName}', 'NavController#update');
Route::delete('/nav/{navName}', 'NavController#destroy');
Below is my github repository link, if you want to take a look at my full code, or you want to try run the code in your Integrated Development Environment.
https://github.com/xiaoheixi/blog
Thanks for reading! :D
If is complaining that it can't find a variable called $navContent.
I can't see you passing it to either of the views you are calling from your index() functions.
return view('navManagement', compact('navs'));
return view('pageManagement', compact('pages'));
You would need to set that varaible and pass it to the view
// Get the nav content however you want, this is just a crude example
$navContent = $this->getMyNavContent();
return view('navManagement', [
'navs' => $navs,
'navContent' => $navContent
]);
I'm guessing you want to find a way to embed the dynamic nav without having to add the navContent every time you render a view, as that's what the other answer is suggesting. You could achieve this using a middleware, say dynamicNav and registering your routes under that middleware group.
In that middleware you can do all the logic of fetching the nav content and then use something like merge, as shown here:
$request->merge(['dynamicNav' => $navContent]);
This way your middleware will add the data to every request which goes through it, although I wouldn't recommend this solution.
What I would do is cache the nav content and retrieve in the view using the cache() helper, then override the save() method of the model to also update the cache when the DB is updated (to avoid duplicate code, you could create a trait for the fetching of the nav). Example:
// in your model
public function save(array $options = [])
{
Cache::put('nav-content', getNavContent());
parent::save();
}

Display primary video for specific ad/property in Laravel

I am working on a project for ads/properties in Laravel. I have gallery of multiple videos for each individual ad. I want to be able to select one of those videos with radio button and make it primary video for that ad (show that particular video next to ad). I have has many relationship between property and video. I am trying to update my is_main_video column to be 1 if it is main or 0 if it isn't and then display that video if it is 1 in my view. I am having trouble to write that method in my controller I get success message but my is_main_video column remains null. Any help is appreciated. Here are my tables and code.
properties (id, title, location, price)
videos (id, filename_video, model_id, is_main_video)
In videos table model_id column is foreign key that connects to properties table.
PropertyController.php
public function update(StorePropertyInfo $request, Property $property, Video $video)
{
$videoExtensions = ['mp4', '3gp', 'wmv', 'flv', 'avi'];
$image_arr = array_filter(explode(',', $request->image), 'strlen');
foreach ($image_arr as $key => $value) {
$file = explode('.', $value);
ext = end($file);
if (in_array($ext, $videoExtensions)) {
$query = Property::query();
if ($request->has('radio')) {
$request->get('radio');
}
if ($request->radio) {
$query->whereHas('videos', function ($query) use ($request) {
$query->where('is_main_video', 'like', '%' . $request->radio . '%');
});
}
$data = $query;
$video->where('filename_video', $value)
->update([
'model_id' => $property->id,
'is_main_video' => $data
]);
};
$request->validated();
return redirect()
->back()
->with('message', 'Property information updated');
}
}
edit.blade.php
<input type="hidden" id="hideninput" data-src="property/{{$property->id}}/gallery"value="{{old('video',$video)}}" name="video">
#if (old('video', $video))
#foreach (array_filter(explode(',',old('video', $video)), 'strlen') as $key =>$value)
<div id="{{'div_video_'.$key}}" class="col-md-3" style="padding: 15px;">
<input type="radio" name="radio" value="radio">Make main
<button data="{{$key}}" type="button" class="closebuttonvideo">
<span aria-hidden="true">×</span>
</button>
<video name="video" id="{{'video_'.$key}}" data={{$value}} src="/storage/property/{{$property->id}}/gallery/{{$value}}" class="video-js vjs-default-skin" controls preload="auto" data-setup='{"inactivityTimeout": 0}' width="180" height="180"></video>
</div>
#endforeach
#endif
videos table migration
public function up()
{
Schema::table('videos', function (Blueprint $table) {
$table->boolean('is_main_video')->nullable()->default(null);
$table->unique(['model_id', 'is_main_video']);
});
}
Property.php
protected $appends = ['is_main_video'];
public function videos()
{
return $this->hasMany(Video::class, 'model_id');
}
Video.php
public function properties()
{
return $this->belongsTo(Property::class);
}
I would do a partial rewrite, something like this:
PropertyController.php in edit(); Retrieving a property with attached videos.
return view('edit', [
'property' => Property::with('videos')->find(1),
]);
edit.blade.php
#foreach($property->videos as $video)
<input type="radio" name="main_video" value="{{ $video->id }}">Video {{ $video->id }}<br>
#endforeach
PropertyController.php in update(); Toggle the is_main_video attribute of each video of the property.
foreach ($property->videos as $video) {
$video->is_main_video = ($video->id == $request->input('main_video'));
$video->save();
}

Display list Vue Axios with Laravel

I'm new to laravel, axios and vue and I used this tutorial to help make a ToDo list:
I want to tweak the basic tutorial by allowing different users to store and view their tasks. I added new user registration and login, but each user would see everyone's list, not only theirs. So I made a one to many relationship between the User and Task model and added these methods to the models:
class User extends Authenticatable
{
...
public function tasks()
{
return $this->hasMany('App\Task');
}
}
class Task extends Model
{
...
public function user()
{
return $this->belongsTo('App\User');
}
}
I updated TaskController.php and TaskList.vue to display only the active user's tasks, but now in the view no list appears and new tasks can't be added.
Here is the code for the two. Everything is the same as the tutorial, except I commented next to the parts that I added:
<?php
namespace App\Http\Controllers;
use App\Task;
use Illuminate\Http\Request;
class TaskController extends Controller
{
$user = Auth::user(); //Added by me
public function index()
{
return Task::latest()->where('user_id', $user->id)->get(); //Added by me,
//this query returns whats expected in php artisan tinker
//was previously return Task::latest()->get();
//I also tried this: return $this->user->tasks->toJSON()
}
public function store(Request $request)
{
$this->validate($request, [
'body' => 'required|max:500'
]);
return Task::create([
'body' => request('body'),
'user_id' => $user->id //Added by me
]);
}
public function destroy($id)
{
$task = Task::findOrFail($id);
$task->delete();
return 204;
}
}
In TaskList.vue
<template>
<div class='row'>
<h1>My Tasks</h1>
<h4>New Task</h4>
<form action="#" #submit.prevent="createTask()">
<div class="input-group">
<input v-model="task.body" type="text" name="body" class="form-control" autofocus>
<span class="input-group-btn">
<button type="submit" class="btn btn-primary">New Task</button>
</span>
</div>
</form>
<h4>All Tasks</h4>
<ul class="list-group">
<li v-if='list.length === 0'>There are no tasks yet!</li>
<li class="list-group-item" v-for="(task, index) in list">
{{ task.body }}
<button #click="deleteTask(task.id)" class="btn btn-danger btn-xs pull-right">Delete</button>
</li>
</ul>
</div>
</template>
<script>
export default {
data() {
return {
list: [],
task: {
id: '',
body: '',
user_id: '' ///Added by me
}
};
},
created() {
this.fetchTaskList();
},
methods: {
fetchTaskList() {
axios.get('api/tasks').then((res) => {
this.list = res.data;
});
},
createTask() {
axios.post('api/tasks', this.task)
.then((res) => {
this.task.body = '';
this.task.user_id = ''; ///added by me
this.edit = false;
this.fetchTaskList();
})
.catch((err) => console.error(err));
},
deleteTask(id) {
axios.delete('api/tasks/' + id)
.then((res) => {
this.fetchTaskList()
})
.catch((err) => console.error(err));
},
}
}
</script>
</script>
The app worked until I added the few lines mentioned above. Now nothing shows in the display and no new tasks can be added. I am new to laravel and totally new to axios and vue, but to me it seems like what I added should work. There are no error messages when I run it, it just doesn't produce what I want.

Laravel 5.5 multiple image upload

I try to use dropzoneJS in order to upload multiple image for my products and so far I can save images in database, also in images folder but I have problem with getting product id to relate each image to products.
Here is what I have:
Databases
Products (where my products including info will save)
Images (where my images including product id will save screenshot provided )
Models
Product:
public function images()
{
return $this->morphMany(Image::class, 'imageable');
}
Image:
class Image extends Model
{
protected $fillable = ['name'];
public function imageable()
{
return $this->morphTo();
}
public function product()
{
return $this->belongsTo(Product::class);
}
}
Image Schema
public function up()
{
Schema::create('images', function (Blueprint $table) {
$table->increments('id');
$table->integer('imageable_id')->nullable();
$table->string('imageable_type')->nullable();
$table->string('name');
$table->timestamps();
});
}
ImageController
class ImageController extends Controller
{
public function dropzone()
{
return view('dropzone-view');
}
public function dropzoneStore(Request $request)
{
// works
$file = $request->file('file');
$filename = 'product' . '-' . time() . '.' . $file->getClientOriginalExtension();
$filePath = public_path('images/');
$request->file('file')->move($filePath, $filename);
return Image::create([
'name' => $filename,
'imageable_id' => $request->input('imageable_id'),
])->id;
}
}
Product Create (Blade)
// Form
{!! Form::open([ 'route' => [ 'dropzone.store' ], 'files' => true, 'enctype' => 'multipart/form-data', 'class' => 'dropzone mt-20', 'id' => 'my-awesome-dropzone' ]) !!}
<div class="fallback">
<input name="file" type="file" multiple />
</div>
<input type="hidden" name="imageIds[]" value="">
{{Form::close()}}
// Javascript
<script type="text/javascript">
Dropzone.autoDiscover = false;
var myDropzone = new Dropzone("form#my-awesome-dropzone", {
headers: {
"X-CSRF-TOKEN": $("meta[name='csrf-token']").attr("content")
},
acceptedFiles: ".jpeg,.jpg,.png,.gif",
dictDefaultMessage: "Drag an image here to upload, or click to select one",
maxFiles: 15, // Maximum Number of Files
maxFilesize: 8, // MB
addRemoveLinks: true,
});
myDropzone.on("success", function (response) {console.log(response.xhr.response); });
</script>
Any idea?
Code for controller:
class ImageController extends Controller
{
public function dropzone($id)
{
$product = Product::find($id);
return view('dropzone-view')
->withProduct($porduct);
}
public function dropzoneStore(Request $request)
{
// works
$file = $request->file('file');
$filename = 'product' . '-' . time() . '.' . $file->getClientOriginalExtension();
$filePath = public_path('images/');
$request->file('file')->move($filePath, $filename);
return Image::create([
'name' => $filename,
'imageable_id' => $request->input('imageable_id'),
])->id;
}
}
Code on blade view:
{!! Form::open([ 'route' => [ 'dropzone.store' ], 'files' => true, 'enctype' => 'multipart/form-data', 'class' => 'dropzone mt-20', 'id' => 'my-awesome-dropzone' ]) !!}
<div class="fallback">
<input name="imageable_id" type="hidden" value="{{$product->id}}" />
<input name="file" type="file" multiple />
</div>
{{Form::close()}}
Try this hope this should get you going. This is one of many way to make this thing work.
this is a morpic relation and this is how you get morphic relation
$post = App\Post::find(1);
foreach ($post->comments as $comment) {
//
}
read about it here polymorphic-relations
What i normally do is,
After you upload a picture, return the ID of the newly created image (you already do that in ImageController)
On your product page, in the dropzone 'success' callback you can read the the image ID and add it to an hidden array input field
In your controller you have to create the new product, and then after saving it , you can attach the images to the correct product, because now you have the id's of the images + the product instance has been made.

TokenMismatchException in laravel 5.4 with image upload

I'm building a Laravel 5.4 application that let's you upload an image to each registered entry. I was using the intervention image package but realized I needed a way to enable image cropping and rotation (iphone images are rotated when uploaded for some reason), so I decided to use the jquery plugin Slim Cropper. I've added the necessary files to my code but can't succesfully upload an image.
Slim Cropper offers two ways to upload an image: through a regular form which gives me the "TokenMismatchException in VerifyCsrfToken.php (line 68)" after submitting, and an ajax form that simply shows a "cannot upload" message. I've tried both ways with different changes but can't get it to work. All my classes/controllers check for authentication, and I have tried sending the csrf token every way I could think of, all show the same error.
UPDATE: As per the suggestions in the comments, I've moved csrf token right after <form>, I've updated the input file names to match those from the example and attempted to debug through middleware with no error messages whatsoever. The TokenMismatchException error is no longer an issue, but once the form is submitted I get the error Constant expression contains invalid operations in Slim.php (line 106) for public static function saveFile($data, $name, $path = public_path('/uploads/mascotas-img/'), $uid = true). Still have no fix for this.
Here's the code:
Routes
Route::post('/mascotas/avatar', 'PetsController#avatar');
Pets Controller
use App\Slim;
public function avatar(Request $request)
{
if ( $request->avatar )
{
// Pass Slim's getImages the name of your file input, and since we only care about one image, postfix it with the first array key
$image = Slim::getImages('avatar')[0];
$mascota_num = $image['meta']->petId;
// Grab the ouput data (data modified after Slim has done its thing)
if ( isset($image['output']['data']) )
{
// Original file name
$name = $image['output']['name'];
//$name = $request->input('mascota_num');
// Base64 of the image
$data = $image['output']['data'];
// Server path
$path = public_path('/uploads/mascotas-img/');
// Save the file to the server
$file = Slim::saveFile($data, $name, $path);
// Get the absolute web path to the image
$imagePath = public_path('/uploads/mascotas-img/' . $file['name']);
DB::table('mascotas')
->where('num',$mascota_num)
->update(['foto' => $imagePath]);
//$mascota->foto = $imagePath;
//$mascota->save();
}
}
return redirect()->back()->with('success', "User's profile picture has been updated!");
}
Slim Class
namespace App;
abstract class SlimStatus {
const Failure = 'failure';
const Success = 'success';
}
class Slim {
public static function getImages($inputName = 'slim') {
$values = Slim::getPostData($inputName);
// test for errors
if ($values === false) {
return false;
}
// determine if contains multiple input values, if is singular, put in array
$data = array();
if (!is_array($values)) {
$values = array($values);
}
// handle all posted fields
foreach ($values as $value) {
$inputValue = Slim::parseInput($value);
if ($inputValue) {
array_push($data, $inputValue);
}
}
// return the data collected from the fields
return $data;
}
// $value should be in JSON format
private static function parseInput($value) {
// if no json received, exit, don't handle empty input values.
if (empty($value)) {return null;}
// The data is posted as a JSON String so to be used it needs to be deserialized first
$data = json_decode($value);
// shortcut
$input = null;
$actions = null;
$output = null;
$meta = null;
if (isset ($data->input)) {
$inputData = isset($data->input->image) ? Slim::getBase64Data($data->input->image) : null;
$input = array(
'data' => $inputData,
'name' => $data->input->name,
'type' => $data->input->type,
'size' => $data->input->size,
'width' => $data->input->width,
'height' => $data->input->height,
);
}
if (isset($data->output)) {
$outputData = isset($data->output->image) ? Slim::getBase64Data($data->output->image) : null;
$output = array(
'data' => $outputData,
'width' => $data->output->width,
'height' => $data->output->height
);
}
if (isset($data->actions)) {
$actions = array(
'crop' => $data->actions->crop ? array(
'x' => $data->actions->crop->x,
'y' => $data->actions->crop->y,
'width' => $data->actions->crop->width,
'height' => $data->actions->crop->height,
'type' => $data->actions->crop->type
) : null,
'size' => $data->actions->size ? array(
'width' => $data->actions->size->width,
'height' => $data->actions->size->height
) : null
);
}
if (isset($data->meta)) {
$meta = $data->meta;
}
// We've sanitized the base64data and will now return the clean file object
return array(
'input' => $input,
'output' => $output,
'actions' => $actions,
'meta' => $meta
);
}
// $path should have trailing slash
public static function saveFile($data, $name, $path = public_path('/uploads/mascotas-img/'), $uid = true) {
// Add trailing slash if omitted
if (substr($path, -1) !== '/') {
$path .= '/';
}
// Test if directory already exists
if(!is_dir($path)){
mkdir($path, 0755);
}
// Let's put a unique id in front of the filename so we don't accidentally overwrite older files
if ($uid) {
$name = uniqid() . '_' . $name;
}
$path = $path . $name;
// store the file
Slim::save($data, $path);
// return the files new name and location
return array(
'name' => $name,
'path' => $path
);
}
public static function outputJSON($status, $fileName = null, $filePath = null) {
header('Content-Type: application/json');
if ($status !== SlimStatus::Success) {
echo json_encode(array('status' => $status));
return;
}
echo json_encode(
array(
'status' => $status,
'name' => $fileName,
'path' => $filePath
)
);
}
/**
* Gets the posted data from the POST or FILES object. If was using Slim to upload it will be in POST (as posted with hidden field) if not enhanced with Slim it'll be in FILES.
* #param $inputName
* #return array|bool
*/
private static function getPostData($inputName) {
$values = array();
if (isset($_POST[$inputName])) {
$values = $_POST[$inputName];
}
else if (isset($_FILES[$inputName])) {
// Slim was not used to upload this file
return false;
}
return $values;
}
/**
* Saves the data to a given location
* #param $data
* #param $path
*/
private static function save($data, $path) {
file_put_contents($path, $data);
}
/**
* Strips the "data:image..." part of the base64 data string so PHP can save the string as a file
* #param $data
* #return string
*/
private static function getBase64Data($data) {
return base64_decode(preg_replace('#^data:image/\w+;base64,#i', '', $data));
}
}
Picture submit form (tokenmismatch error)
<form action="{{ url('mascotas/avatar') }}" method="post" enctype="multipart/form-data">
<div class="modal-body">
<div class="slim" data-label="Agregar imagen aquí" data-size="400, 400" data-ratio="1:1" data-meta-pet-id="{{ $mascota->num }}">
#if ( $mascota->foto )
<img src="{{ url('/uploads/mascotas-img/'.$mascota->foto) }}" />
#endif
<input type="file" name="avatar" required />
{{ csrf_field() }}
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
<button type="submit" class="btn btn-red">Cambiar Foto</button>
</div>
</form>
Alternate submit form (error message)
<div class="modal-body">
<div class="slim" data-label="Agregar imagen aquí" data-size="400, 400" data-ratio="1:1" data-service="{{ url('mascotas/avatar') }}" data-meta-pet-id="{{ $mascota->num }}">
#if ( $mascota->foto )
<img src="{{ url('/uploads/mascotas-img/'.$mascota->foto) }}" />
#endif
<input type="file" name="avatar" />
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
<button type="submit" class="btn btn-red">Cambiar Foto</button>
</div>
Slim image cropper website with examples http://slimimagecropper.com/
My original upload form through laravel image intervetion, this works with no problems at upload, but would very much like to replace with one of the above.
<form enctype="multipart/form-data" action="{{ url('mascotas/foto') }}" method="POST">
<div class="modal-body">
<img class="mascota-avatar" src="{{ url('/uploads/mascotas-img/'.$mascota->foto) }}">
<div class="clearfix"></div>
<input type="file" name="foto">
<input type="hidden" name="_token" value="{{ csrf_token() }}">
<input type="hidden" name="mascota_num" value="{{ $mascota->num }}">
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
<button type="submit" class="btn btn-red">Cambiar Foto</button>
</div>
</form>
Thanks for any help!
You should include the {{ csrf_field() }} on each of your forms, for the Ajax one, you could send the token as header.

Categories