how to use main.php in modules in Yii - 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

Related

Save data in a model from a different view

I have two tables, business and review business, in review business I have user_id, business_id,rating and review field. I want to write a review, for that purpose, I need rating and review fields from the review business table, and I want to show them in a view of business which I called (user_business.php). I successfully bring the rating and review field from the review_business table, and user is able to give his review, but the thing is the data is not saving in the review business model. I am posting my code, please find the error.
This is my business controller.
<?php
class BusinessController extends RController
{
/**
* #var string the default layout for the views. Defaults to '//layouts/column2', meaning
* using two-column layout. See 'protected/views/layouts/column2.php'.
*/
public $layout='//layouts/admin';
/**
* #return array action filters
*/
public function filters()
{
return array(
// 'accessControl', // perform access control for CRUD operations
// 'postOnly + delete', // we only allow deletion via POST request
'rights',
);
}
/**
* 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', // allow all users to perform 'index' and 'view' actions
'actions'=>array('index','view'),
'users'=>array('*'),
),
array('allow', // allow authenticated user to perform 'create' and 'update' actions
'actions'=>array('create','update'),
'users'=>array('#'),
),
array('allow', // allow admin user to perform 'admin' and 'delete' actions
'actions'=>array('admin','delete'),
'users'=>array('admin'),
),
array('deny', // deny all users
'users'=>array('*'),
),
);
}
/**
* Displays a particular model.
* #param integer $id the ID of the model to be displayed
*/
public function actionView($id)
{
$this->render('view',array(
'model'=>$this->loadModel($id),
));
}
public function actionUserbusiness($id) // this is userbusiness
{
//render main layout
$this->layout='main';
$model2 = new ReviewBusiness(); getting fields of review business
$this->render('userbusiness',array(
'model'=>$this->loadModel($id),
'reviewmodel'=>$model2
));
}
/**
* Creates a new model.
* If creation is successful, the browser will be redirected to the 'view' page.
*/
public function actionCreate()
{
$model=new Business;
// Uncomment the following line if AJAX validation is needed
// $this->performAjaxValidation($model);
if(isset($_POST['Business']))
{
$rnd = rand(0, 9999); // generate random number between 0-9999
$model->attributes = $_POST['Business'];
$uploadedFile = CUploadedFile::getInstance($model, 'image');
$fileName = "{$rnd}-{$uploadedFile}"; // random number + file name
$model->image = $fileName;
if ($model->save()) {
$uploadedFile->saveAs(Yii::app()->basePath . '/../img/' . $fileName);
$this->redirect(array('view', 'id' => $model->id));
}
}
$this->render('create', array(
'model' => $model,
));
}
/**
* Updates a particular model.
* If update is successful, the browser will be redirected to the 'view' page.
* #param integer $id the ID of the model to be updated
*/
public function actionUpdate($id)
{
$model=$this->loadModel($id);
// Uncomment the following line if AJAX validation is needed
// $this->performAjaxValidation($model);
if(isset($_POST['Business']))
{
//$model->attributes=$_POST['Business'];
$_POST['Business']['image'] = $model->image;
$model->attributes=$_POST['Business'];
$uploadedFile=CUploadedFile::getInstance($model,'image');
if($model->save())
{ if(!empty($uploadedFile)) // check if uploaded file is set or not
{
$uploadedFile->saveAs(Yii::app()->basePath.'/../img/'.$model->image);
}
$this->redirect(array('view','id'=>$model->id));
}
}
$this->render('update',array(
'model'=>$model,
));
}
/**
* Deletes a particular model.
* If deletion is successful, the browser will be redirected to the 'admin' page.
* #param integer $id the ID of the model to be deleted
*/
public function actionDelete($id)
{
if(Yii::app()->request->isPostRequest)
{
// we only allow deletion via POST request
$this->loadModel($id)->delete();
// if AJAX request (triggered by deletion via admin grid view), we should not redirect the browser
if(!isset($_GET['ajax']))
$this->redirect(isset($_POST['returnUrl']) ? $_POST['returnUrl'] : array('admin'));
}
else
throw new CHttpException(400,'Invalid request. Please do not repeat this request again.');
}
/**
* Lists all models.
*/
public function actionIndex()
{
$dataProvider=new CActiveDataProvider('Business');
$this->render('index',array(
'dataProvider'=>$dataProvider,
));
}
/**
* Manages all models.
*/
public function actionAdmin()
{
$model=new Business('search');
$model->unsetAttributes(); // clear any default values
if(isset($_GET['Business']))
$model->attributes=$_GET['Business'];
$this->render('admin',array(
'model'=>$model,
));
}
/**
* Returns the data model based on the primary key given in the GET variable.
* If the data model is not found, an HTTP exception will be raised.
* #param integer $id the ID of the model to be loaded
* #return Business the loaded model
* #throws CHttpException
*/
public function loadModel($id)
{
$model=Business::model()->findByPk($id);
if($model===null)
throw new CHttpException(404,'The requested page does not exist.');
return $model;
}
/**
* Performs the AJAX validation.
* #param Business $model the model to be validated
*/
protected function performAjaxValidation($model)
{
if(isset($_POST['ajax']) && $_POST['ajax']==='business-form')
{
echo CActiveForm::validate($model);
Yii::app()->end();
}
}
}
Now view of userbusiness is given below. Oh and I am using dzraty extension for rating.
<?php $form=$this->beginWidget('bootstrap.widgets.BsActiveForm', array(
'id'=>'review-business-form',
// Please note: When you enable ajax validation, make sure the corresponding
// controller action is handling ajax validation correctly.
// There is a call to performAjaxValidation() commented in generated controller code.
// See class documentation of CActiveForm for details on this.
'enableAjaxValidation'=>false,
)); ?>
<?php
$this->widget('ext.DzRaty.DzRaty', array(
'model' => $reviewmodel,
'attribute' => 'rating',
)); ?>
</ul>
</div>
<div class="form-group">
<label>Review Text</label>
<?php echo $form->textarea($reviewmodel,'review',array('maxlength'=>500)); ?>
</div>
<?php echo BsHtml::submitButton('Submit', array('color' => BsHtml::BUTTON_COLOR_PRIMARY)); ?>
<?php $this->endWidget(); ?>

Laravel 5 - Middleware always restricts access while being logged in

I've got a quite annoying problem at the moment :( hope you can help me out there ...
I'm using the basic login form of laravel at the moment with a pretty much untouched User model.
So, the logging in apparently works (tracked it), but whenever I try to restrict content access (restrict routes) with the help of a middleware, it denies the access.
So, why does it deny me the access if I'm apparently logged in?
I'm really not seeing what I'm doing wrong.
Thanks for your help in advance! (for further information I copied you my middleware, authcontroller and my user model)
<?php namespace App;
use Illuminate\Auth\Authenticatable;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Auth\Passwords\CanResetPassword;
use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
class User extends Model implements AuthenticatableContract, CanResetPasswordContract
{
use Authenticatable, CanResetPassword;
/**
* The database table used by the model.
*
* #var string
*/
protected $table = 'user';
/**
* The attributes excluded from the model's JSON form.
*
* #var array
*/
protected $hidden = ['password', 'remember_token'];
public $timestamps = false;
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = ['user_properties_ID', 'email', 'password'];
}
I'm also using the standard AuthController
<?php namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use Illuminate\Contracts\Auth\Guard;
use Illuminate\Contracts\Auth\Registrar;
use Illuminate\Foundation\Auth\AuthenticatesAndRegistersUsers;
class AuthController extends Controller {
/*
|--------------------------------------------------------------------------
| Registration & Login Controller
|--------------------------------------------------------------------------
|
| This controller handles the registration of new users, as well as the
| authentication of existing users. By default, this controller uses
| a simple trait to add these behaviors. Why don't you explore it?
|
*/
use AuthenticatesAndRegistersUsers;
/**
* Create a new authentication controller instance.
*
* #param \Illuminate\Contracts\Auth\Guard $auth
* #param \Illuminate\Contracts\Auth\Registrar $registrar
* #return void
*/
public function __construct(Guard $auth, Registrar $registrar)
{
$this->auth = $auth;
$this->registrar = $registrar;
// $this->middleware('guest', ['except' => 'getLogout', 'getLogin']);
}
}
And my middleware looks like this:
<?php namespace App\Http\Middleware;
use Closure;
use Illuminate\Contracts\Auth\Guard;
use Illuminate\Http\RedirectResponse;
use Illuminate\Support\Facades\Auth;
class RedirectIfAuthenticated {
/**
* The Guard implementation.
*
* #var Guard
*/
protected $auth;
/**
* Create a new filter instance.
*
* #param Guard $auth
* #return void
*/
public function __construct(Guard $auth)
{
$this->auth = $auth;
}
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
if (! $this->auth->check())
{
// return $next($request);
return response('Unauthorized.', 401);
// return redirect()->intended();
// return new RedirectResponse(url('/trainingsplan-hinzufuegen'));
}
return $next($request);
}
}
routes.php
<?php
/*
|--------------------------------------------------------------------------
| Home
|--------------------------------------------------------------------------
*/
Route::group(['prefix' => '', 'middleware' => 'guest', 'namespace' => 'Modules\TrainaryCore\Http\Controllers', 'as' => 'home'], function()
{
Route::get('/home', 'TrainaryCoreController#render');
});
/*
|--------------------------------------------------------------------------
| Registrierung
|--------------------------------------------------------------------------
*/
Route::group(['prefix' => '', 'namespace' => 'Modules\TrainaryCore\Http\Controllers', 'as' => 'registrieren'], function()
{
Route::get('/registrieren', 'TrainaryCoreController#render');
Route::post('/registrieren', 'RegistrationController#validateForm');
});
/*
|--------------------------------------------------------------------------
| Trainingsplan
|--------------------------------------------------------------------------
*/
Route::group(['prefix' => '', 'middleware' => 'guest', 'namespace' => 'Modules\TrainaryCore\Http\Controllers', 'as' => 'schedule'], function()
{
Route::get('/trainingsplan-hinzufuegen', 'TrainaryCoreController#render');
Route::post('/trainingsplan-hinzufuegen', 'ScheduleController#validateForm');
});
Well, what's happening is ok. If you use the GUEST middleware, it'll only allow you in if you are a guest. You gotta use the AUTH middleware.
okay, Laravel uses as a standard 'id' for tables ...
so, if you want to rename it you have to add following to your Model:
protected $primaryKey = 'ID';
that's the solution boys

How do I change default pagination attributes in Yii?

In my Yii project, I want the default pageSize for pagination to be fetched automatically, so I don't have to specify it in all the widgets that use pagination. But I can't seem to find a way to globally change the pagination class, without editing Yii source files. Is this possible?
Please create file on /components/WidgetFactory.php with below code.
<?php
/**
* Custom WidgetFactory class
* Provides two new events:
* - onBeforeCreateWidget
* - onAfterCreateWidget
*
* Allows for advanced global widget alteration, going a step further than CWidgetFactory's
* typical process which allows you to define default values for widgets.
*
*/
class WidgetFactory extends CWidgetFactory
{
/**
* Raised right BEFORE a widget is created.
* #param CEvent $event the event parameter
*/
public function onBeforeCreateWidget(CEvent $event)
{
$this->raiseEvent('onBeforeCreateWidget',$event);
}
/**
* Raised right AFTER a widget is created.
* #param CEvent $event the event parameter
*/
public function onAfterCreateWidget(CEvent $event)
{
$this->raiseEvent('onAfterCreateWidget',$event);
}
/**
* Creates a new widget based on the given class name and initial properties.
* #param CBaseController $owner the owner of the new widget
* #param string $className the class name of the widget. This can also be a path alias (e.g. system.web.widgets.COutputCache)
* #param array $properties the initial property values (name=>value) of the widget.
* #return CWidget the newly created widget whose properties have been initialized with the given values.
*/
public function createWidget($owner,$className,$properties=array())
{
if (! ($this->hasEventHandler('onBeforeCreateWidget') || $this->hasEventHandler('onAfterCreateWidget')))
return parent::createWidget($owner, $className, $properties);
$event=new WidgetEvent($this, $owner, $className, $properties);
if ($this->hasEventHandler('onBeforeCreateWidget'))
$this->raiseEvent('onBeforeCreateWidget', $event);
$event->widget=parent::createWidget($owner, $className, $properties);
if ($this->hasEventHandler('onAfterCreateWidget'))
$this->raiseEvent('onAfterCreateWidget', $event);
return $event->widget;
}
}
class WidgetEvent extends CEvent
{
/**
* #var CBaseController Owner of the new widget
*/
public $owner;
/**
* #var string Widget class name
*/
public $className;
/**
* #var CWidget The newly created widget
*/
public $widget;
/**
* Constructor.
* #param WidgetFactory $sender The WidgetFactory instance
* #param CBaseController $owner The owner of the new widget
* #param string $className The class name of the widget. This can also be a path alias.
* #param array $params The initial property values (name=>value) of the widget.
*/
public function __construct(WidgetFactory $sender, CBaseController $owner, $className, array $params=array())
{
parent::__construct($sender, $params);
$this->owner=$owner;
$this->className=$className;
}
}
And correct config/main.php like below.
return array(
// ...
'components'=>array(
// ...
'widgetFactory'=>array(
'class'=>'WidgetFactory',
'onAfterCreateWidget'=>function(WidgetEvent $event){
static $defaultPageSize=50; // YOUR_DEFAULT_PAGESIZE_HERE
$widget=$event->widget;
if ($widget instanceof CBaseListView) {
/** #var CBaseListView $widget */
if ($widget->dataProvider!==null && $widget->dataProvider->pagination!==false)
$widget->dataProvider->pagination->pageSize=$defaultPageSize;
}
},
),
// ...
),
);
Please notice default pageSize above on config code . I think it will solve your problem.

DHTMLX integration with yii framework not working?

I integrated dhtmlx with yii frame work based on the instruction given in their site.( DHTMLX With YII )
here my controller file code,
include_once(YII_BASE_PATH . "/dhtmlx/connector/grid_connector.php");
include_once(YII_BASE_PATH . "/dhtmlx/connector/scheduler_connector.php");
include_once(YII_BASE_PATH . "/dhtmlx/connector/db_phpyii.php");
class EventsController extends Controller
{
public function accessRules()
{
return array(
array('allow', // allow all users to perform 'index' and 'view' actions
'actions'=>array('index','view','grid','scheduler'),
'users'=>array('*'),
),
array('allow', // allow authenticated user to perform 'create' and 'update' actions
'actions'=>array('create','update'),
'users'=>array('#'),
),
array('allow', // allow admin user to perform 'admin' and 'delete' actions
'actions'=>array('admin','delete'),
'users'=>array('admin'),
),
array('deny', // deny all users
'users'=>array('*'),
),
);
}
public function actionGrid()
{
// $this->render('grid'); //loads the 'grid' view that we will create later
$model = new Events();
$this->render('grid',array(
'model'=>$model,
));
}
public function actionGrid_data()
{
//$model = new Events;
$grid = new GridConnector(Events::model(), "PHPYii");
$grid->configure("-","event_id", "start_date, end_date, event_name");
$grid->render();
}
}
==============================================================================
my view file
<script src="<?php echo AT::getAdminBaseUrl()?>/dhtmlx/grid/dhtmlxcommon.js" type="text/javascript" charset="utf-8"></script>
<script src="<?php echo AT::getAdminBaseUrl()?>/dhtmlx/grid/dhtmlxgrid.js" type="text/javascript" charset="utf-8"></script>
<script src="<?php echo AT::getAdminBaseUrl()?>/dhtmlx/grid/dhtmlxgridcell.js" type="text/javascript" charset="utf-8"></script>
<script src="<?php echo AT::getAdminBaseUrl()?>/dhtmlx/dhtmlxdataprocessor.js" type="text/javascript" charset="utf-8"></script>
<script src="<?php echo AT::getAdminBaseUrl()?>/dhtmlx/connector/connector.js" type="text/javascript" charset="utf-8"></script>
<link rel="stylesheet" href="<?php echo AT::getAdminBaseUrl()?>/dhtmlx/grid/dhtmlxgrid.css" type="text/css" media="screen" title="no title" charset="utf-8">
<link rel="stylesheet" href="<?php echo AT::getAdminBaseUrl()?>/dhtmlx/grid/skins/dhtmlxgrid_dhx_skyblue.css" type="text/css" media="screen" title="no title" charset="utf-8">
<div id="grid_here" style="width:600px; height:400px;"> </div>
<?php
// $this->widget('zii.widgets.CListView', array(
// 'dataProvider'=>$dataProvider,
// 'itemView'=>'_view',
// ));
?>
<script type="text/javascript">
mygrid = new dhtmlXGridObject('grid_here');
mygrid.setHeader("Start date,End date,Text");
mygrid.init();
mygrid.loadXML("./grid_data"); //refers to the 'Grid_data' action we created in the previous step
var dp = new dataProcessor("./grid_data"); //refers to the 'Grid_data' action as well
dp.init(mygrid);
</script>
===========================================================================
my modal file
<?php
/**
* This is the model class for table "vendor".
*
* The followings are the available columns in table 'vendor':
* #property integer $id
* #property string $vendor_name
* #property string $vendor_description
* #property string $status
*/
class Events extends CActiveRecord
{
/**
* Returns the static model of the specified AR class.
* #param string $className active record class name.
* #return Vendor the static model class
*/
public static function model($className=__CLASS__)
{
return parent::model($className);
}
/**
* #return string the associated database table name
*/
public function tableName()
{
return 'events';
}
/**
* #return array validation rules for model attributes.
*/
public function rules()
{
// NOTE: you should only define rules for those attributes that
// will receive user inputs.
return array(
array('event_name', 'length', 'max'=>255),
// The following rule is used by search().
// Please remove those attributes that should not be searched.
array('start_date,end_date,event_name', 'safe', 'on'=>'search'),
);
}
/**
* #return array relational rules.
*/
public function relations()
{
// NOTE: you may need to adjust the relation name and the related
// class name for the relations automatically generated below.
return array(
);
}
/**
* #return array customized attribute labels (name=>label)
*/
public function attributeLabels()
{
return array(
'event_id' => 'Event Id',
'start_date' => 'Start Date',
'end_date' => 'End Date',
'event_name' => 'Event Name',
);
}
/**
* Retrieves a list of models based on the current search/filter conditions.
* #return CActiveDataProvider the data provider that can return the models based on the search/filter conditions.
*/
public function search()
{
// Warning: Please modify the following code to remove attributes that
// should not be searched.
$criteria=new CDbCriteria;
$criteria->compare('event_id',$this->event_id);
$criteria->compare('start_date',$this->start_date,true);
$criteria->compare('end_date',$this->end_date,true);
$criteria->compare('event_name',$this->event_name,true);
return new CActiveDataProvider($this, array(
'criteria'=>$criteria,
));
}
}
when I run the action grid i got the error in the popup window like below,
I don't know what is the issue?. I doubt that may be '$grid = new GridConnector(Events::model(), "PHPYii"); ' this one causes the problem.
How can I resolve this one?. Can anyone help me?.
Yes. I found answer, I need to edit the core extension file dhtmlx/connector/db_phpyii.php
like below, (Remove &-reference operator).
Shows – $temp[]=&$obj->getAttributes();
Should read – $temp[]=$obj->getAttributes();
Ref: http://www.dhtmlx.com/blog/?p=1648
Please have a look at the question: Strict Standards: Only variables should be assigned by reference PHP 5.4
Looks like you're using strict standards and passing an object with a reference operator in line 16 of /dhtmlx/connector/db_phpyii.php.

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.