Octobercms Upload Files - php

How to solve the error?
this is my htm code (button upload)
{{ form_open({files: true, request: 'onFileUpload'}) }}
<!--File Input-->
<input type="file" name="file-upload" required="required">
<!--File Input-->
<!--Submit/Upload Button-->
<button type="submit">Upload</button>
{{ form_close() }}
this is the component php code
public function onFileUpload()
{
$file = new System\Models\File;
$file->data = Input::file('file-upload');
$file->save();
// Attach the uploaded file to your model
$model->file()->add($file);
// The above line assumes you have proper attachOne or attachMany relationships defined on your model
$model->file_path = url('/') . $model->file->getPath();
$model->save();
return Redirect::back();
}
is this the proper attachMany relationship?
public $attachMany = [
'files' => 'System\Models\File',
];
}
I'm not very sure about the code cause I'm new to October cms
Can anyone show some examples?
How to create a drag and drop file uploader component?

You need to new up an instance of the model that you've defined you relationship in and set it as your $model variable.
For example.. your model class could look like this.
class User extends Model
{
public attachMany [
'files' => 'System\Models\File'
];
}
And then in your component onFileUpload()
$model = new User;
$model->files()->add($file);
$model->file_path = url('/') . $model->file->getPath();
$model->save();
Also, just take notice that your attachMany relationship in your model class is defined as files but you're trying to use it with
$model->file()->add();
It should be
$model->files()->add();

Related

Symfony form rendered in twig template as controller is not submitting

I'd like to have simple "Search" input field in base.html.twig. Normally I would need to write code to maintain form in every route. To solve this problem I decided to create separate controller with route to render it directly in base.html.twig template:
<div class="top-middle col-12 col-md-6 d-flex order-2 order-md-1">
{{ render(controller("App\\Controller\\SearchController::searchProduct"))}}
</div>
It works find except nothing happens when the form is submitted. I tried it in normal way in one of my routes and it was working fine. So don't know where the problem is.
My SearchController with route which is rendered in twig :
class SearchController extends AbstractController
{
#[Route('search-product', name: 'search_product')]
public function searchProduct(Request $request)
{
$searchForm = $this->createForm(SearchProductType::class);
$searchForm->handleRequest($request);
if ($searchForm->isSubmitted() && $searchForm->isValid()) {
dump('Form submitted');
}
return $this->render('components/search-input.html.twig', [
'searchForm' => $searchForm->createView()
]);
}
}
Search input.html.twig component:
<div class="top-search">
<i class="bi-search top-search__icon"></i>
{{ form(searchForm) }}
</div>
and the main controller which renders index.html.twig with base.html.twig:
#[Route('/', name: 'home')]
public function index(FileHandler $fileHandler, SessionInterface $session, Request $request): Response
{
$products = $this->doctrine->getRepository(Product::class)->getProducts('Dresses', 4);
$products = $this->addPathToImages($products, 'Dresses');
return $this->render('shop/index.html.twig', [
'products' => $products
]);
}
The line
dump('Form submitted');
is not executed when the form is submitted. Page refreshes but nothing happens.
I think the whole logic should stay in this route/controller or I am missing something?
As requested I publish my solution:
Instead of embedding controller directly in Twig file and decided to handle my little form (just Search input, submitted by pressing "enter") with js. The reason for this is that it's impossible to redirect from embedded controller.
Code in twig:
<form id="top-search-form">
<div class="top-search">
<input id="search-string"
class="top-search__input" type="search"
placeholder="Search shop">
</div>
</form>
and code written in Javascript (requires FOSJSRouting Bundle):
const routes = require('/public/js/fos_js_routes.json');
import Routing from '/vendor/friendsofsymfony/jsrouting-bundle/Resources/public/js/router.min.js';
Routing.setRoutingData(routes);
document.addEventListener('DOMContentLoaded', function() {
const searchForm = document.getElementById('top-search-form');
searchForm.addEventListener('submit', function(e) {
e.preventDefault();
const searchString = document.getElementById('search-string').value;
var url = Routing.generate('items_filter', {
'searchText': searchString
});
location.href = url;
});
})

How to associate files to post with Laravel 5.6

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
}

What is VOLT macro for rendering a <form> tag?

In Phalcon one can create a custom form extending Phalcon\Form\Form. This class has method called setAction, but I cannot find any info on how to automatically render a <form> tag with action that I specified.
My form is called RegisterForm, and I am passing it to VOLT view like this:
$this->view->registerForm = new RegisterForm(new UserModel());
In my VOLT template I can use the registerForm.render('username') macro to automatically render input field registered in my form.
Is there any macro that will create the following?
<form action="/register" method="post">
assuming that I've used:
$this->setAction($this->url->get('index/register'));
in the form definition.
After another day of research, and chatting at Phalcon's Slack channel, I've came to realization that, there is no built-in way of doing what I intended.
Simplest solution is to create a BaseForm class that extends Phalcon\Forms\Form. Here is an example:
<?php
namespace MyNamespace\Common\Form;
use Phalcon\Forms\Form;
class BaseForm extends Form {
/**
* Creates <form> tag in VOLT view.
*/
public function startForm($method = 'post') {
return '<form action="'.$this->getAction().'" method="'.$method.'">';
}
/**
* Creates </form> tag in VOLT view.
*/
public function endForm() {
return '</form>';
}
/**
* Pushes all errors to flash container.
*/
public function error($name) {
if($this->hasMessagesFor($name)) {
foreach($this->getMessagesFor($name) as $message) {
$this->flash->error($message);
}
return true;
}
return false;
}
}
With this, after extending a custom form definition, I'm able to use:
# IndexController.php
public function index() {
$this->view->registerForm = new RegisterForm();
}
# index.volt
{{ registerForm.startForm() }}
{{ registerForm.endForm() }}
{{ registerForm.error('username') }}
Here is how to render a form in Volt:
{{ form('products/save', 'method': 'post') }}
<label for="name">Name</label>
{{ text_field("name", "size": 32) }}
<label for="type">Type</label>
{{ select("type", productTypes, 'using': ['id', 'name']) }}
{{ submit_button('Send') }}
{{ end_form() }}
More info in the Docs.
You can also check Phalcon's project Vokuro for more examples.
Update: Lukasz asked for a solution to render form tag from custom form element with it's properties. Phlacon Form Decorators is the closest solution to the problem I can find.

Laravel -5: How do I get my form inputs to validate (among other things..)?

I have a few problems.
I can't seem to display the saved data inside my form inputs.
I can't get my urls to validate unique.
My controller code looks very redundant.
Getting the urls to validate unique takes priority though.
Also I created the table for sharing social links with a user one to many relationship. I think thats correct. If not, please correct me.
update Just a thought...I think I'm probably complicating things by only have a single 'type' column. It would be easier if I had a column for each type of link i.e facebook col, twitter col etc. I just didn't want empty columns if user didn't provide info for some services
Heres my code:
UPDATE I gave up and just added individual columns for the different types of urls and changed to a one-to-one relationship.
form
{!! Form::model($user_links,['method' => 'PATCH', 'action'=> ['UserController#update_social']]) !!}
<div class='row form-group'>
<div class='col-md-2'>
{!! Form::label('facebook', 'Facebook Username') !!}
</div>
<div class='col-md-7'>
{!! Form::text('facebook', '',['class'=>'form-control']) !!}
</div>
</div>
<div class='row form-group'>
<div class='col-md-2'>
{!! Form::label('twitter', 'Twitter Username') !!}
</div>
<div class='col-md-7'>
{!! Form::text('twitter', null,['class'=>'form-control']) !!}
</div>
</div>
<div class='row form-group'>
<div class='col-md-2'>
{!! Form::label('reddit', 'Reddit Username') !!}
</div>
<div class='col-md-7'>
{!! Form::text('reddit', null,['class'=>'form-control']) !!}
</div>
</div>
<div class='row form-group'>
<div class='col-md-3'>
{!! Form::submit('Save Changes',['class'=>'btn btn-md btn-success']) !!}
</div>
</div>
{!! Form::close() !!}
controllers
public function show_social(Request $request){
$user_links= $request->user()->links;
return view('user.edit.social_connect',compact('user_links'));
}
public function update_social(SocialRequest $request){
$facebook= Input::get('facebook');
$twitter= Input::get('twitter');
$reddit= Input::get('reddit');
$user = $request->user();
$this->validate($request,['url'=>'unique']);
if(Input::has('facebook')||Input::has('google')||Input::has('reddit')||Input::has('twitter'))
{
if($facebook != ""){
$link = new SocialLinks();
$link->type = 'facebook';
$link->url='https//www.facebook.com/'.$facebook;
$link->user_id=$user->id;
$link->save();
}
if($twitter != ""){
$link = new SocialLinks();
$link->type = 'twitter';
$link->url='https//www.twitter.com/'.$twitter;
$link->user_id=$user->id;
$link->save();
}
if($reddit != ""){
$link = new SocialLinks();
$link->type = 'reddit';
$link->url='https//www.reddit.com/user'.$reddit;
$link->user_id=$user->id;
$link->save();
}
return Redirect::back()->with('message','Your profile has been updated');
}
return Redirect::back();
}
my model file
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
use Eloquent;
class SocialLinks extends Eloquent{
protected $table= 'social_links';
protected $fillable=[
'type',
'url'
];
public function user()
{
return $this->belongsTo('App\User');
}
}
?>
my request
<?php
namespace App\Http\Requests;
use App\Http\Requests\Request;
class SocialRequest extends Request
{
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
return [
'url'=>'unique|user_id'
];
}
}
Okay, there are a few things wrong here. Your request file is being used incorrectly. You need a model for that, unless ofcourse you're just getting "request file" and "model" mixed up. For the purpose of this comment, I'm going to use Laravel's validation method from within the controller.
Something worth noting, your "url" is not present within the form. The validation looks for a "url" parameter inside of the request, but as you do not appear to be sending that within the form, it is quite redundant. Also, when you use the "unique" validator, you need to supply a database table for it to search and check against the supplied value, in this case; url.
I've added that in, but, really it's not doing anything because the url will always be empty until you supply it in your form, so the request will always pass.
public function show_social(Request $request)
{
$user_links = $request->user()->links;
return view('user.edit.social_connect', compact('user_links'));
}
public function update_social(Request $request)
{
$facebook = $request->facebook;
$twitter = $request->twitter;
$reddit = $request->reddit;
$user = $request->user();
$this->validate($request, [
'url' => 'unique:social_links,column',
]);
if($request->has('facebook') || $request->has('google') || $request->has('reddit') || $request->has('twitter'))
{
if($facebook != ""){
$link = new SocialLinks();
$link->type = 'facebook';
$link->url = 'https//www.facebook.com/'.$facebook;
$link->user_id = $user->id;
$link->save();
}
if($twitter != ""){
$link = new SocialLinks();
$link->type = 'twitter';
$link->url = 'https//www.twitter.com/'.$twitter;
$link->user_id = $user->id;
$link->save();
}
if($reddit != ""){
$link = new SocialLinks();
$link->type = 'reddit';
$link->url = 'https//www.reddit.com/user'.$reddit;
$link->user_id = $user->id;
$link->save();
}
return Redirect::back()->with('message','Your profile has been updated');
}
return Redirect::back();
}
As you can see, I removed the type hinting for your request because what you were actually doing (from what I can tell), was type hinting the model. Your "request file" which you supplied is a model and should be in the App/ directory, and referenced using a namespace.
If you are indeed using that file as a model, then your relationship looks okay, assuming of course you've got the right foreign column setup in your database, referencing the user table.
As for your model binding not working, have you tried dumping the $user_links variable, like so: dd($user_links); - to see if it actually contains anything? As you're using a request there, I cannot tell where you're getting the information.
Hopefully this helps, if you have any more questions, feel free to ask.

Laravel file upload confusion

So, I am trying to battle the old file upload inside of the Laravel framework but getting a bit lost. I have managed to get the upload to work so the file uploads and saved into an assets folder with a random string name.
This is the form:
<form action="{{ URL::route('account-upload') }}" method="post">
{{ Form::label('file','Upload File') }}
{{ Form::file('file') }}
<br />
{{ Form::submit('Upload') }}
{{ Form::token() }}
</form>
This is the Route:
Route::get('/account/upload', array(
'as' => 'account-upload',
'uses' => 'AccountController#getUpload'
));
Route::post('/account/upload', function(){
if (Input::hasFile('file')){
$dest = 'assets/uploads/';
$name = str_random(6).'_'. Input::file('file')->getClientOriginalName();
Input::file('file')->move($dest,$name);
return Redirect::to('/account/upload')
->withGlobal('Your image has been uploaded');
}
});
this is the method inside AccountController:
public function getUpload(){
return View::make('account.upload');
}
public function postUpload() {
$user = User::find(Auth::id());
$user->image = Input::get('file');
}
I am now trying to enable that to push the string name into the database and also be associated with the user who uploaded it and show as their profile image? Ay pointers would be great!
I have created a row inside of the database named 'file' with the type of text....I am not sure on this point of how to store and view the image.
try this
// the view
{{ Form::open(['route' => 'account-upload', 'files' => true]) }}
{{ Form::label('file','Upload File') }}
{{ Form::file('file') }}
<br />
{{ Form::submit('Upload') }}
{{ Form::close() }}
// route.php
Route::get('/account/upload', 'AccountController#upload');
Route::post('/account/upload', [
'as' => 'account-upload',
'uses' => 'AccountController#store'
]);
// AccountController.php
class AccountController extends BaseController {
public function upload(){
return View::make('account.upload');
}
public function store() {
if (Input::hasFile('file')){
$file = Input::file('file');
$dest = public_path().'/assets/uploads/';
$name = str_random(6).'_'. $file->getClientOriginalName();
$file->move($dest,$name);
$user = User::find(Auth::id());
$user->image = $name;
$user->save();
return Redirect::back()
->withGlobal('Your image has been uploaded');
}
}
}
// and to display the img on the view
<img src="assets/upload/{{Auth::user()->image}}"/>
In order to upload a file, you'll need enctype="multipart/form-data" as an attribute on the <form> element.
If you're using the Form::open() method, you can just pass "files" => true here, but this should allow you to actually use Input::file() correctly.
Next, when actually dealing with the file, you'll need to use something like storage_path() or public_path() and give an absolute path to the file's destination when moving it.
And a tip: you fetch an authed user's model by calling Auth::user().

Categories