Call to a member function update() on null in laravel 9 - laravel-8

What is wrong with this function? I ve got error on this line:
$bookShelf->update($request->all());
My Controller
<?php
namespace App\Http\Controllers;
use App\Models\BookShelf;
use App\Models\Book;
use App\Models\Category;
use App\Http\Requests\StoreBookShelfRequest;
use App\Http\Requests\UpdateBookShelfRequest;
class BookShelfController extends Controller
{
/**
* Display a listing of the resource.
*
* #return \Illuminate\Http\Response
*/
public function index()
{
$bookshelves = BookShelf::with('book')->latest()->get();
// $bookshelves = BookShelf::all();
$model = new BookShelf();
$books = Book::with('category')->latest()->get();
// $books = Book::all();
$categories = Category::with(['users.books.shelf']);
return view('admin.bookshelves.index', compact('bookshelves', 'books', 'model', 'categories'));
}
/**
* Show the form for creating a new resource.
*
* #return \Illuminate\Http\Response
*/
public function create()
{
$model = new BookShelf;
$categories = Category::all();
$books = Book::with('category')->latest()->get();
return view('admin.bookshelves.create', compact('categories', 'model', 'books'));
}
/**
* Store a newly created resource in storage.
*
* #param \App\Http\Requests\StoreBookShelfRequest $request
* #return \Illuminate\Http\Response
*/
public function store(StoreBookShelfRequest $request)
{
BookShelf::create($request->all());
return redirect('admin_area/shelves')->with('success', 'Selamat Data Berhasil Ditambahkan');
}
/**
* Display the specified resource.
*
* #param \App\Models\BookShelf $bookShelf
* #return \Illuminate\Http\Response
*/
public function show(BookShelf $bookShelf)
{
//
}
/**
* Show the form for editing the specified resource.
*
* #param \App\Models\BookShelf $bookShelf
* #return \Illuminate\Http\Response
*/
public function edit($shelf_code)
{
$model = BookShelf::find($shelf_code);
$categories = Category::all();
$books = Book::with('category')->latest()->get();
return view('admin.bookshelves.edit', compact('categories', 'model', 'books'));
}
/**
* Update the specified resource in storage.
*
* #param \App\Http\Requests\UpdateBookShelfRequest $request
* #param \App\Models\BookShelf $bookShelf
* #return \Illuminate\Http\Response
*/
public function update(UpdateBookShelfRequest $request, BookShelf $bookShelf)
{
$bookShelf = BookShelf::find($bookShelf->shelfcode);
$bookShelf->update($request->all());
return redirect('admin_area/bookshelves')->with('success', 'Selamat Data Berhasil Di Ubah');
}
/**
* Remove the specified resource from storage.
*
* #param \App\Models\BookShelf $bookShelf
* #return \Illuminate\Http\Response
*/
public function destroy(BookShelf $bookShelf, $id)
{
$bookShelf = BookShelf::find($id);
$bookShelf->delete();
return redirect('admin_area/shelves')->with('success', "Data berhasil disimpan");
}
}
My Model
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class BookShelf extends Model
{
use HasFactory;
protected $guarded = ['id'];
protected $load = ['category', 'book'];
public function category()
{
return $this->belongsTo(Category::class);
}
public function book()
{
return $this->belongsTo(Book::class);
}
public function getRouteKeyName()
{
return 'shelfcode';
}
}
My Edit View
#extends('layouts.main')
#section('title', 'Edit Data Buku')
#section('content')
<div class="container">
<div class="row mt-3 d-flex justify-content-center">
<div class="col-md-9 justify-content-center">
<div class="card card-primary card-outline">
<div class="card-header">
<h5 class="m-0">Edit Data Rak Buku</h5>
</div>
<div class="card-body">
<h6 class="card-title"></h6>
<form method="POST" action="{{ route('shelves.update', $model->shelfcode) }}"
enctype="multipart/form-data">
#csrf
{{-- <input type="hidden" name="_method" value="PATCH"> --}}
#method('PUT')
#include('admin.bookshelves.form')
<div class="form-group">
<button class="btn btn-warning btn-sm glyphicon glyphicon-save">
<span class="fas fa-edit"> Edit Data Buku</span>
</button>
</div>
</form>
{{-- #endsection --}}
</div>
</div>
</div>
</div>
</div>
#endsection

Looks like you're querying your BookShelf model by the wrong key. You can also remove $bookShelf = BookShelf::find($bookShelf->shelfcode); from the update function since it is already injected by the framework when you use model binding (https://laravel.com/docs/9.x/routing#route-model-binding).

When you have this common error, there is no trap, it litteraly means that you are trying to call update on null.
It's exactly like doing null->update($request->all()) (and you can try, you'll have the same error).
The only explanation here is that $bookShelf = BookShelf::find($bookShelf->shelfcode); returns null.
Regarding the structure itself,
public function update(UpdateBookShelfRequest $request, BookShelf $bookShelf)
{
$bookShelf = BookShelf::find($bookShelf->shelfcode);
//...
}
makes no sense since the whole purpose of using implicit route binding is to avoid the manual query you are making to retrieve $bookShelf. It should already be the BookShelf you need.

Related

Laravel 5.7 variable being lowercased in HTML <option> tag

I'm trying to make a ternary operation in my option tag. But when I call the variable, it becomes to lowercase and laravel could not find it.
Here is my code:
<select name="media_type" id="media_type" class="">
<option value="">Select an option</option>
<option value="image" {{ $campBanner->media_type == 'image' ? 'selected' : '' }}>Image</option>
<option value="video" {{ $campBanner->media_type == 'video' ? 'selected' : '' }}>Video</option>
</select>
And here is the result of the laravel's exception:
<select name="media_type" id="media_type" class="">
<option value="">Select an option</option>
<option value="image" <?php echo e($campbanner->media_type == 'image' ? 'selected' : ''); ?>>Image</option>
<option value="video" <?php echo e($campbanner->media_type == 'video' ? 'selected' : ''); ?>>Video</option>
</select>
ErrorException (E_ERROR)
Undefined variable: campbanner
Is it a bug? Or I just messed up something?
UPDATE
Here is my controller:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\CampBanner;
use App\Http\Requests\StoreCampBanner;
class CampBannerController extends Controller
{
/**
* Display a listing of the resource.
*
* #return \Illuminate\Http\Response
*/
public function index()
{
return view('CampBanner.index', [
'campBanner' => CampBanner::all()
]);
}
/**
* Show the form for creating a new resource.
*
* #return \Illuminate\Http\Response
*/
public function create()
{
return view('CampBanner.create');
}
/**
* Store a newly created resource in storage.
*
* #param \Illuminate\Http\Request $request
* #return \Illuminate\Http\Response
*/
public function store(StoreCampBanner $request)
{
CampBanner::create(
$request->validated()
);
return ['message' => 'Banner Camp baru telah ditambahkan'];
}
/**
* Display the specified resource.
*
* #param \App\CampBanner $campBanner
* #return \Illuminate\Http\Response
*/
public function show(CampBanner $campBanner)
{
return view('CampBanner.show', compact('campBanner'));
}
/**
* Show the form for editing the specified resource.
*
* #param \App\CampBanner $campBanner
* #return \Illuminate\Http\Response
*/
public function edit(CampBanner $campBanner)
{
return view('CampBanner.edit', compact('campBanner'));
}
/**
* Update the specified resource in storage.
*
* #param \Illuminate\Http\Request $request
* #param \App\CampBanner $campBanner
* #return \Illuminate\Http\Response
*/
public function update(StoreCampBanner $request, CampBanner $campBanner)
{
$campBanner->fill(
$request->validated()
)->save();
return ['message' => 'Camp Banner berhasil diperbarui'];
}
/**
* Remove the specified resource from storage.
*
* #param \App\CampBanner $campBanner
* #return \Illuminate\Http\Response
*/
public function destroy(CampBanner $campBanner)
{
$campBanner->delete();
return ['message' => 'Camp Banner berhasil dihapus.'];
}
}
Put your controller codes for better help ..

Confused about prestashop PDF generated process. Where is the code to handle the logic?

I want to deep understand prestahop inside structure and amend some parts. I am stoped in the PDF. I want can't find the controller used to handle the AdminPdf and generateDeliverySlipPDF
{if $order->delivery_number}
<a class="btn btn-default _blank" href="{$link->getAdminLink('AdminPdf')|escape:'html':'UTF-8'}&submitAction=generateDeliverySlipPDF&id_order={$order->id}">
<i class="icon-truck"></i>
</a>
{/if}
Who can help me figure out the inside processes? I can't find the methods to handle generateDeliverySlipPDF.
AdminPdfController is located at /controllers/admin/AdminPdfController.php.
The submitAction=generateDeliverySlipPDF part of the url will call the method processGenerateDeliverySlipPDF() inside this controller.
Here is this method:
public function processGenerateDeliverySlipPDF()
{
if (Tools::isSubmit('id_order')) {
$this->generateDeliverySlipPDFByIdOrder((int)Tools::getValue('id_order'));
} elseif (Tools::isSubmit('id_order_invoice')) {
$this->generateDeliverySlipPDFByIdOrderInvoice((int)Tools::getValue('id_order_invoice'));
} elseif (Tools::isSubmit('id_delivery')) {
$order = Order::getByDelivery((int)Tools::getValue('id_delivery'));
$this->generateDeliverySlipPDFByIdOrder((int)$order->id);
} else {
die(Tools::displayError('The order ID -- or the invoice order ID -- is missing.'));
}
}
In this Controller you'll find other methods as this one to generate Invoices, Order, ... and other PDFs.
Feel free to ask if you need more informations.
EDIT:
If you want to change format in a proper way you'll have to override those classes:
/override/classes/pdf/PDFGenerator.php:
<?php
/**
* #since 1.5
*/
class PDFGenerator extends PDFGeneratorCore
{
/**
* #param bool $use_cache
* #param string $orientation
* #param string $format
*/
public function __construct($use_cache = false, $orientation = 'P', $format = 'A4')
{
TCPDF::__construct($orientation, 'mm', $format, true, 'UTF-8', $use_cache, false);
$this->setRTL(Context::getContext()->language->is_rtl);
}
}
/override/classes/pdf/PDF.php:
<?php
/**
* #since 1.5
*/
class PDF extends PDFCore
{
/**
* #param $objects
* #param $template
* #param $smarty
* #param string $orientation
*/
public function __construct($objects, $template, $smarty, $orientation = 'P', $format = 'A4')
{
parent::__construct($objects, $template, $smarty, $orientation);
$this->pdf_renderer = new PDFGenerator((bool)Configuration::get('PS_PDF_USE_CACHE'), $orientation, $format);
}
}
/override/controllers/admin/AdminPdfController.php:
<?php
class AdminPdfController extends AdminPdfControllerCore
{
public function generatePDF($object, $template)
{
switch($template) {
case PDF::TEMPLATE_DELIVERY_SLIP:
$format = array(210, 50000); // Replace with your desired size
break;
default:
$format = 'A4';
}
$pdf = new PDF($object, $template, Context::getContext()->smarty, 'P', $format);
$pdf->render();
}
}
Now you can specify the format for each PDF.
You will find informations about $format at this place
This code has not been tested but should work as expected. Let me know if you encounter any issue.
You will need to delete /cache/class_index.php after adding those overrides to clear Prestashop internal classes path cache.
thank you for this topic,
I would like to ask you for the case of generating pdf in front?
i.e
this is a part of history.tpl
`{if $order.details.invoice_url}
<i class="material-icons"></i>`
i found $order.details.invoice_url is define in OrderPresenter.php
and OrderPresenter use HistoryController to get the invoice_url.
So i take a look in historyController
if ((bool) Configuration::get('PS_INVOICE') && OrderState::invoiceAvailable($order->current_state) && count($order->getInvoicesCollection())) {
$url_to_invoice = $context->link->getPageLink('pdf-invoice', true, null, 'id_order='.$order->id);
if ($context->cookie->is_guest) {
$url_to_invoice .= '&secure_key='.$order->secure_key;
}
}
getPageLink use "pdf-invoice" ,i take a look for getPageLink Method and see that "pdf-invoice" is a controller...
the trouble is i don't know where is this controller?
help please

how to use main.php in modules in Yii

I'm creating an admin dashboard in Yii. here is my structure
- Protected
|
- Modules
|
-- Views
|
---Layouts
|
--- main.php
--- column1.php
--- column2.php
|
- Themes
|
-- Bootstrap
|
--- Views
|
--- Admin
|
---- Layouts
|
---- main.php
for some reason, my admin panel keeps reading the main.php in the bootstrap folder instead of /modules/admin/views/layouts/main.php
/**
* Base class for all admin controllers.
*/
class AdminController extends CController
{
/**
* #var string the default layout for the controller view. Defaults to '/layouts/column1',
* meaning using a single column layout. See 'protected/modules/admin/views/layouts/column2.php'.
*/
public $layout = '/layouts/column2';
/**
* #var string the pageTitle of the current page.
*/
public $pageTitle = "";
/**
* #var array the breadcrumbs of the current page. The value of this property will
* be assigned to {#link CBreadcrumbs::links}. Please refer to {#link CBreadcrumbs::links}
* for more details on how to specify this property.
*/
public $breadcrumbs = array();
/**
* #var array admin context menu items. This property will be assigned to {#link TbMenu::items}.
*/
public $adminMenu = array();
/**
* #return array action filters
*/
public function filters()
{
return array(
'accessControl', // perform access control for CRUD operations
);
}
/**
* Specifies the access control rules.
* This method is used by the 'accessControl' filter.
* #return array access control rules
*/
public function accessRules()
{
return array(
array('allow',
'users' => array('#'),
//'expression' => 'Yii::app()->user->isAdmin'
),
array('deny', // deny all users
'users' => array('*'),
),
);
}
public function beforeRender($view)
{
if ($this->adminMenu && !Yii::app()->user->isGuest)
$this->renderPartial('/layouts/clips/_admin_clip');
return parent::beforeRender($view);
}
}
here is my column2.php
<?php /* #var $this Controller */ ?>
<?php $this->beginContent('/layouts/main'); ?>
<div class="row">
<div class="span2" id="sidebar">
<?php
//a clip is a piece of captured output that can be inserted elsewhere.
if (isset($this->clips['adminMenuClipID']))
echo $this->clips['adminMenuClipID'];
?>
</div>
<div class="span10" id="main-content">
<?php echo $content; ?>
</div>
</div>
<?php $this->endContent(); ?>
how do i make it ready main.php from /modules/admin/views/layouts/main.php ?
You need to alter the path to the decorative view that your view calls in CController::beginContent():
$this->beginContent('application.modules.admin.views.layouts.column2')
assuming the path is modules/admin/views/layouts/column2.php

Laravel Auth::check() only returns true on post page

I am new at Laravel and having some struggles with simple login and authorization pages.
I followed an awesome video tutorial by laracasts.com (credits for that one, really helpful).
My situation:
When implementing authorization to my page, the page after the login succeeds the authorization check.
So: loginform > press button > You are now logged in.
My problem:
After I press the back button and refresh, it still gives the login form. It shouldn't.
routes.php
<?php
Route::get('login', 'SessionsController#create');
Route::get('logout', 'SessionsController#destroy');
Route::resource('users', 'UsersController');
Route::resource('sessions', 'SessionsController');
Route::get('admin', function(){
return 'Admin page';
})->before('auth');
Route::get('dashboard', ['before' => 'auth', function(){
return 'Dashboard';
}]);
SessionsController.php:
<?php
class SessionsController extends BaseController{
public function create()
{
if ( Auth::check() )
{
Redirect::to('/admin');
}
return View::make('sessions.create');
}
public function store()
{
if( Auth::attempt(Input::only('email', 'password')) )
{
// if(Auth::check())
// {
// return 'check worked!';
// }
return 'Welcome ' . Auth::user()->username; //You are now logged in
}
return 'Failed';
}
public function destroy()
{
Auth::logout();
return Redirect::to('sessions.create');
}
}
User.php
<?php
use Illuminate\Auth\UserInterface;
use Illuminate\Auth\Reminders\RemindableInterface;
class User extends Eloquent implements UserInterface, RemindableInterface {
public $timestamps = true;
protected $fillable = ['username', 'email', 'password'];
protected $guarded = ['id'];
public static $rules = [
'username' => 'required',
'password' => 'required'
];
public $errors;
/**
* The database table used by the model.
*
* #var string
*/
protected $table = 'users';
/**
* The attributes excluded from the model's JSON form.
*
* #var array
*/
protected $hidden = array('password');
/**
* Get the unique identifier for the user.
*
* #return mixed
*/
public function getAuthIdentifier()
{
return $this->getKey();
}
/**
* Get the password for the user.
*
* #return string
*/
public function getAuthPassword()
{
return $this->password;
}
/**
* Get the e-mail address where password reminders are sent.
*
* #return string
*/
public function getReminderEmail()
{
return $this->email;
}
public function isValid()
{
$validation = Validator::make($this->attributes, static::$rules );
if($validation->passes() )
return true;
$this->errors = $validation->messages();
return false;
}
}
create.blade.php
#extends('layouts.default')
#section('content')
<h1>Create new user</h1>
{{Form::open([ 'route' => 'users.store' ]) }}
<div>
{{Form::label('username', 'Username: ')}}
{{Form::text('username')}}
{{$errors->first('username')}}
</div>
<div>
{{Form::label('password', 'Password: ')}}
{{Form::password('password')}}
{{$errors->first('password')}}
</div>
<div>
{{Form::submit('Create User')}}
</div>
{{Form::close() }}
#stop
So to speak: It never goes to the 'admin' route.
Your authentication code is correct and working. What you have is something going wrong in any other part of your Laravel application, web server or even PHP.
Since we are not seeing all your code, we can just guess, so my first one would be the Session not being stored correctly. Currently logged users are stored in Laravel Session. So, check your session driver, if it's in 'native', change it to 'database', but you'll have to create a sessions table, look at the docs. If you are already using 'database', change it back to 'native' or even 'file'.
Instead of run
return 'Welcome ' . Auth::user()->username; //You are now logged in
Please try
return Redirect::to('admin');

Multiple file upload with Symfony2

I'm trying to upload multiple files via a form, but I can only upload one file at a time, the last one I mark in the browser. Is there a way to upload more images with Symfony2 using a simple form?
Here is the twig template of the form I'm using to be able to mark more than one file:
{{ form_widget(form.post_image, { 'attr': {'multiple': 'multiple' }}) }}
Ok binding issue solved (enctype syntax error) : i'll give you the code i use. maybe it will help...
I have a Gallery Entity
class Gallery
{
protected $id;
protected $name;
protected $description;
private $urlName;
public $files; // the array which will contain the array of Uploadedfiles
// GETTERS & SETTERS ...
public function getFiles() {
return $this->files;
}
public function setFiles(array $files) {
$this->files = $files;
}
public function __construct() {
$files = array();
}
}
I have a form class that generate the form
class Create extends AbstractType {
public function buildForm(FormBuilder $builder, array $options) {
$builder->add('name','text',array(
"label" => "Name",
"required" => TRUE,
));
$builder->add('description','textarea',array(
"label" => "Description",
"required" => FALSE,
));
$builder->add('files','file',array(
"label" => "Fichiers",
"required" => FALSE,
"attr" => array(
"accept" => "image/*",
"multiple" => "multiple",
)
));
}
}
Now in the controller
class GalleryController extends Controller
{
public function createAction() {
$gallery = new Gallery();
$form = $this->createForm(new Create(), $gallery);
// Altering the input field name attribute
$formView = $form->createView();
$formView->getChild('files')->set('full_name', 'create[files][]');
$request = $this->getRequest();
if($request->getMethod() == "POST")
{
$form->bindRequest($request);
// print "<pre>".print_r($gallery->getFiles(),1)."</pre>";
if($form->isValid())
{
// Do what you want with your files
$this->get('gallery_manager')->save($gallery);
return $this->redirect($this->generateUrl("_gallery_overview"));
}
}
return $this->render("GalleryBundle:Admin:create.html.twig", array("form" => $formView));
}
}
Hope this help...
NB: If someone know a better way to alter this f** name attribute, maybe in the FormView class or by declaring a new field type, feel free to show us your method...
No extra classes needed (except the gallery_manger service but the issue you describe happens before...)
I don't really know what's wrong. Check for your template (maybe wrong enctype... or name attr missmatching)
first try to do a single file upload, check the documentation:
file Field Type
How to handle File Uploads with Doctrine
Once it works, you have to edit some lines.
add input file multiple attribute.
append [] at the end of the input file name attribute (mine is
create...[] because my form class name is create, if your is
createType it will be createType...[])
init $files as an array.
Copy/paste your code here.
All the suggestions I've found here are workarounds for the real situation.
In order to be able to have multiple attachments, you should use form collection.
Quote from the documentation:
In this entry, you'll learn how to create a form that embeds a collection of many other forms. This could be useful, for example, if you had a Task class and you wanted to edit/create/remove many Tag objects related to that Task, right inside the same form.
http://symfony.com/doc/2.0/cookbook/form/form_collections.html
Example case: You have a document, which form is specified by DocumentType. The document must have multiple attachments, which you can have by defining AttachmentType form and adding it as a collection to the DocumentType form.
For sf > 2.2 :
In you form type class, add this overrided method :
public function finishView(FormView $view, FormInterface $form, array $options) {
$view->vars['form']->children['files']->vars['full_name'] .= '[]';
}
Note that i try to do the same thing in sf2 using this syntax:
In the controller:
public function stuffAction() {
$form = $this->createFormBuilder()
->add('files','file',array(
"attr" => array(
"accept" => "image/*",
"multiple" => "multiple",
)
))
->getForm();
$formView = $form->createView();
$formView->getChild('files')->set('full_name', 'form[files][]');
// name param (eg 'form[files][]') need to be the generated name followed by []
// try doing this : $formView->getChild('files')->get('full_name') . '[]'
$request = $this->getRequest();
if($request->getMethod() == "POST") {
$form->bindRequest($request);
$data = $form->getData();
$files = $data["files"];
// do stuff with your files
}
}
return $this->render('Bundle:Dir:index.html.twig',array("form" => $formView));
}
$files will be an array of uploaded files...
Calling $form->createView() to alter the name attribute is certainly not the best way / cleanest way to do it but it's the only one i found that keeps the csrf functionality working, because altering the name attribute in a twig template makes it invalid...
Now I still have an issue using a form class which generate the form, I don't know why during the binding of the form data & object attached to the form my array of uploaded files is transformed in array of (file) name ???
use this methode :
$form = $this->createFormBuilder()
->add('attachments','file', array('required' => true,"attr" => array(
"multiple" => "multiple",
)))
->add('save', 'submit', array(
'attr' => array('class' => 'btn btn-primary btn-block btn-lg'),
'label' => 'save'
))
->getForm();
then you add [] to the name of your input via jQuery :
<input id="form_attachments" name="form[attachments]" required="required" multiple="multiple" type="file">
jQuery code :
<script>
$(document).ready(function() {
$('#form_attachments').attr('name',$('#form_attachments').attr('name')+"[]");
});
</script>
Here is easy example to upload multiple files. I have similar problem with upload files.
https://github.com/marekz/example_symfony_multiply_files_example
For symfony 3.*
First: Both form declatartion:
<?php
namespace AppBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use AppBundle\Form\FilesType;
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
class UserType extends AbstractType
{
/**
* {#inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name')
->add('lastName')
->add('files', CollectionType::class,array(
'entry_type' => FilesType::class,
'allow_add' => true,
'by_reference' => false,
))
;
}
/**
* {#inheritdoc}
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'AppBundle\Entity\User'
));
}
/**
* {#inheritdoc}
*/
public function getBlockPrefix()
{
return 'appbundle_user';
}
}
<?php
namespace AppBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class FilesType extends AbstractType
{
/**
* {#inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('file');
}
/**
* {#inheritdoc}
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'AppBundle\Entity\Files'
));
}
/**
* {#inheritdoc}
*/
public function getBlockPrefix()
{
return 'appbundle_files';
}
}
Now, my entities:
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
/**
* User
*
* #ORM\Table(name="user")
* #ORM\Entity(repositoryClass="AppBundle\Repository\UserRepository")
*/
class User {
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="name", type="string", length=255)
*/
private $name;
/**
* #var string
*
* #ORM\Column(name="lastName", type="string", length=255)
*/
private $lastName;
/**
* #ORM\ManyToMany(targetEntity="Files", cascade={"persist"})
*/
private $files;
function __construct() {
$this->files = new ArrayCollection();
}
/**
* Get id
*
* #return int
*/
public function getId() {
return $this->id;
}
/**
* Set name
*
* #param string $name
*
* #return User
*/
public function setName($name) {
$this->name = $name;
return $this;
}
/**
* Get name
*
* #return string
*/
public function getName() {
return $this->name;
}
/**
* Set lastName
*
* #param string $lastName
*
* #return User
*/
public function setLastName($lastName) {
$this->lastName = $lastName;
return $this;
}
/**
* Get lastName
*
* #return string
*/
public function getLastName() {
return $this->lastName;
}
/**
* Get files
*
* #return ArrayCollection
*/
function getFiles() {
return $this->files;
}
/**
* Set files
* #param type $files
*/
function setFiles($files) {
$this->files = $files;
}
}
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
/**
* Files
*
* #ORM\Table(name="files")
* #ORM\Entity(repositoryClass="AppBundle\Repository\FilesRepository")
*/
class Files
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="file", type="string", length=255, unique=true)
* #Assert\NotBlank(message="Please, upload the product brochure as a PDF file.")
* #Assert\File(mimeTypes={ "application/pdf" })
*/
private $file;
/**
*
* #return Files
*/
function getUser() {
return $this->user;
}
/**
* Get id
*
* #return int
*/
public function getId()
{
return $this->id;
}
/**
* Set file
*
* #param string $file
*
* #return Files
*/
public function setFile($file)
{
$this->file = $file;
return $this;
}
/**
* Get file
*
* #return string
*/
public function getFile()
{
return $this->file;
}
}
Finaly, Symfony Controller:
/**
* Creates a new user entity.
*
* #Route("/new", name="user_new")
* #Method({"GET", "POST"})
*/
public function newAction(Request $request) {
$user = new User();
$form = $this->createForm('AppBundle\Form\UserType', $user);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$attachments = $user->getFiles();
if ($attachments) {
foreach($attachments as $attachment)
{
$file = $attachment->getFile();
var_dump($attachment);
$filename = md5(uniqid()) . '.' .$file->guessExtension();
$file->move(
$this->getParameter('upload_path'), $filename
);
var_dump($filename);
$attachment->setFile($filename);
}
}
$em = $this->getDoctrine()->getManager();
$em->persist($user);
$em->flush();
return $this->redirectToRoute('user_show', array('id' => $user->getId()));
}
return $this->render('user/new.html.twig', array(
'user' => $user,
'form' => $form->createView(),
));
}
You need to alter the input file name attribute which need to map an array.
<input type="file" name="name[]" multiple />
Methods getChild and set() were removed in 2.3.
Instead of this you should use children[] and vars properties
before:
$formView->getChild('files')->set('full_name', 'form[files][]');
after:
$formView->children['files']->vars = array_replace($formView->children['files']->vars, array('full_name', 'form[files][]'));
Symfony introduced 'multiple' option to file field type in symfony 2.5
$builder->add('file', 'file', array('multiple' => TRUE));
What would happen if there would be some validation errors? Will Symfony Form repost multiple file upload field. Because I tried it and I think for this purpose you need to use collection of file fields. Than symfony form must render all fields have added before correctly.