What does CDBException mean here and how do I resolve it? - yii

Please, I am totally new to Yii1.1, I am following a video tutorial and I have benn trying to follow up closely. I am trying to create and update the album model as indicated in the video tutorial. I typed everything the presenter typed: my codes are given below:
The AlbumController
class AlbumController extends Controller
{
/**
* #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/column2';
/**
* #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
);
}
/**
* 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),
));
}
/**
* Creates a new model.
* If creation is successful, the browser will be redirected to the 'view' page.
*/
public function actionCreate()
{
$model=new Album;
// Uncomment the following line if AJAX validation is needed
$this->performAjaxValidation($model);
if(isset($_POST['Album']))
{
$model->attributes=$_POST['Album'];
if($model->save()){
//$this->redirect(array('view','id'=>$model->id));
Yii::app()->user->setFlash('saved', 'Data saved!');
$this->redirect(array('update','id'=>$model->id));
}
else{
Yii::app()->user->setFlash('failure', 'Data not saved!');
}
}
$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['Album']))
{
$model->attributes=$_POST['Album'];
if($model->save()){
//$this->redirect(array('view','id'=>$model->id));
Yii::app()->user->setFlash('saved', "Data saved!");
$this->redirect(array('update','id'=>$model->id));
}else{
Yii::app()->user->setFlash('failure', "Data not saved!");
}
}
$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)
{
$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'));
}
/**
* Lists all models.
*/
public function actionIndex()
{
$dataProvider=new CActiveDataProvider('Album');
$this->render('index',array(
'dataProvider'=>$dataProvider,
));
}
/**
* Manages all models.
*/
public function actionAdmin()
{
$model=new Album('search');
$model->unsetAttributes(); // clear any default values
if(isset($_GET['Album']))
$model->attributes=$_GET['Album'];
$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 Album the loaded model
* #throws CHttpException
*/
public function loadModel($id)
{
$model=Album::model()->findByPk($id);
if($model===null)
throw new CHttpException(404,'The requested page does not exist.');
return $model;
}
/**
* Performs the AJAX validation.
* #param Album $model the model to be validated
*/
protected function performAjaxValidation($model)
{
if(isset($_POST['ajax']) && $_POST['ajax']==='album-form')
{
echo CActiveForm::validate($model);
Yii::app()->end();
}
}
}
The Album model class
/**
* This is the model class for table "tbl_album".
*
* The followings are the available columns in table 'tbl_album':
* #property integer $id
* #property string $name
* #property string $tags
* #property integer $owner_id
* #property integer $shareable
* #property string $created_dt
*
* The followings are the available model relations:
* #property User $owner
* #property Photo[] $photos
*/
class Album extends CActiveRecord
{
/**
* #return string the associated database table name
*/
public function tableName()
{
return 'tbl_album';
}
/**
* #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('owner_id, shareable, category_id', 'numerical', 'integerOnly'=>true),
array('name, tags', 'length', 'max'=>255),
array('description', 'length', 'max'=>1024),
array('description', 'match', 'pattern'=>'/[\w]+/u'),// \-\_\'\ \,\p{L}0-!
// The following rule is used by search().
// #todo Please remove those attributes that should not be searched.
array('id, name, tags, owner_id, shareable, created_dt', 'safe', 'on'=>'search'),
);
}
/**
* #return array relational rules.
*/
//defined function beforeSave()..
protected function beforeSave(){
if(parent::beforeSave()){
if($this->isNewRecord){
$this->created_dt = new CDbExpression("NOW()");
$this->owner_id = Yii::app()->user->id;
}
return true;
}else
return false;
}
public function scopes(){
return array(
'shareable'=>array(
'order'=>'created_dt DESC',
'condition'=>'shareable=1',
)
);
}
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(
'owner' => array(self::BELONGS_TO, 'User', 'owner_id'),
'photos' => array(self::HAS_MANY, 'Photo', 'album_id'),
);
}
/**
* #return array customized attribute labels (name=>label)
*/
public function attributeLabels()
{
return array(
'id' => 'ID',
'name' => 'Name',
'tags' => 'Tags',
'owner_id' => 'Owner',
'category_id'=>'Category',
'description'=>'Description',
'shareable' => 'Shareable',
'created_dt' => 'Created Dt',
);
}
/**
* Retrieves a list of models based on the current search/filter conditions.
*
* Typical usecase:
* - Initialize the model fields with values from filter form.
* - Execute this method to get CActiveDataProvider instance which will filter
* models according to data in model fields.
* - Pass data provider to CGridView, CListView or any similar widget.
*
* #return CActiveDataProvider the data provider that can return the models
* based on the search/filter conditions.
*/
public function search()
{
// #todo Please modify the following code to remove attributes that should not be searched.
$criteria=new CDbCriteria;
$criteria->compare('name',$this->name,true);
$criteria->compare('tags',$this->tags,true);
$criteria->compare('description',$this->description);
return new CActiveDataProvider($this, array(
'criteria'=>$criteria,
));
}
/**
* Returns the static model of the specified AR class.
* Please note that you should have this exact method in all your CActiveRecord descendants!
* #param string $className active record class name.
* #return Album the static model class
*/
public static function model($className=__CLASS__)
{
return parent::model($className);
}
}
The Photo Model Class
/**
* This is the model class for table "tbl_photo".
*
* The followings are the available columns in table 'tbl_photo':
* #property integer $id
* #property integer $album_id
* #property string $filename
* #property string $caption
* #property string $alt_text
* #property string $tags
* #property integer $sort_order
* #property string $created_dt
* #property string $lastupdate_dt
*
* The followings are the available model relations:
* #property Comment[] $comments
* #property Album $album
*/
class Photo extends CActiveRecord
{
private $_uploads;
/**
* #return string the associated database table name
*/
public function tableName()
{
return 'tbl_photo';
}
/**
* #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('album_id, sort_order', 'numerical', 'integerOnly'=>true),
array('filename', 'length', 'max'=>500),
array('tags', 'length', 'max'=>256),
array('caption, alt_text, created_dt, lastupdate_dt', 'safe'),
// The following rule is used by search().
// #todo Please remove those attributes that should not be searched.
array('id, album_id, filename, caption, alt_text, tags, sort_order, created_dt, lastupdate_dt', '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(
'comments' => array(self::HAS_MANY, 'Comment', 'photo_id'),
'album' => array(self::BELONGS_TO, 'Album', 'album_id'),
);
}
/**
* #return array customized attribute labels (name=>label)
*/
public function attributeLabels()
{
return array(
'id' => 'ID',
'album_id' => 'Album',
'filename' => 'Filename',
'caption' => 'Caption',
'alt_text' => 'Alt Text',
'tags' => 'Tags',
'sort_order' => 'Sort Order',
'created_dt' => 'Created Dt',
'lastupdate_dt' => 'Lastupdate Dt',
);
}
public function getImageParam(){
if(empty($this->_uploads)){
$this->_uploads = Yii::app()->params['uploads']. "/";
return $this->_uploads;
}
}
public function getUrl(){
return $this->getImageParam()."uploads/".CHtml::encode($this->filename);
}
public function getThumb(){
return $this->getImageParam()."thumbs/".CHtml::encode($this->filename);
}
/**
* Retrieves a list of models based on the current search/filter conditions.
*
* Typical usecase:
* - Initialize the model fields with values from filter form.
* - Execute this method to get CActiveDataProvider instance which will filter
* models according to data in model fields.
* - Pass data provider to CGridView, CListView or any similar widget.
*
* #return CActiveDataProvider the data provider that can return the models
* based on the search/filter conditions.
*/
public function search()
{
// #todo Please modify the following code to remove attributes that should not be searched.
$criteria=new CDbCriteria;
$criteria->compare('id',$this->id);
$criteria->compare('album_id',$this->album_id);
$criteria->compare('filename',$this->filename,true);
$criteria->compare('caption',$this->caption,true);
$criteria->compare('alt_text',$this->alt_text,true);
$criteria->compare('tags',$this->tags,true);
$criteria->compare('sort_order',$this->sort_order);
$criteria->compare('created_dt',$this->created_dt,true);
$criteria->compare('lastupdate_dt',$this->lastupdate_dt,true);
return new CActiveDataProvider($this, array(
'criteria'=>$criteria,
));
}
/**
* Returns the static model of the specified AR class.
* Please note that you should have this exact method in all your CActiveRecord descendants!
* #param string $className active record class name.
* #return Photo the static model class
*/
public static function model($className=__CLASS__)
{
return parent::model($className);
}
}
The Photo Model
/**
* This is the model class for table "tbl_photo".
*
* The followings are the available columns in table 'tbl_photo':
* #property integer $id
* #property integer $album_id
* #property string $filename
* #property string $caption
* #property string $alt_text
* #property string $tags
* #property integer $sort_order
* #property string $created_dt
* #property string $lastupdate_dt
*
* The followings are the available model relations:
* #property Comment[] $comments
* #property Album $album
*/
class Photo extends CActiveRecord
{
private $_uploads;
/**
* #return string the associated database table name
*/
public function tableName()
{
return 'tbl_photo';
}
/**
* #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('album_id, sort_order', 'numerical', 'integerOnly'=>true),
array('filename', 'length', 'max'=>500),
array('tags', 'length', 'max'=>256),
array('caption, alt_text, created_dt, lastupdate_dt', 'safe'),
// The following rule is used by search().
// #todo Please remove those attributes that should not be searched.
array('id, album_id, filename, caption, alt_text, tags, sort_order, created_dt, lastupdate_dt', '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(
'comments' => array(self::HAS_MANY, 'Comment', 'photo_id'),
'album' => array(self::BELONGS_TO, 'Album', 'album_id'),
);
}
/**
* #return array customized attribute labels (name=>label)
*/
public function attributeLabels()
{
return array(
'id' => 'ID',
'album_id' => 'Album',
'filename' => 'Filename',
'caption' => 'Caption',
'alt_text' => 'Alt Text',
'tags' => 'Tags',
'sort_order' => 'Sort Order',
'created_dt' => 'Created Dt',
'lastupdate_dt' => 'Lastupdate Dt',
);
}
public function getImageParam(){
if(empty($this->_uploads)){
$this->_uploads = Yii::app()->params['uploads']. "/";
return $this->_uploads;
}
}
public function getUrl(){
return $this->getImageParam()."uploads/".CHtml::encode($this->filename);
}
public function getThumb(){
return $this->getImageParam()."thumbs/".CHtml::encode($this->filename);
}
/**
* Retrieves a list of models based on the current search/filter conditions.
*
* Typical usecase:
* - Initialize the model fields with values from filter form.
* - Execute this method to get CActiveDataProvider instance which will filter
* models according to data in model fields.
* - Pass data provider to CGridView, CListView or any similar widget.
*
* #return CActiveDataProvider the data provider that can return the models
* based on the search/filter conditions.
*/
public function search()
{
// #todo Please modify the following code to remove attributes that should not be searched.
$criteria=new CDbCriteria;
$criteria->compare('id',$this->id);
$criteria->compare('album_id',$this->album_id);
$criteria->compare('filename',$this->filename,true);
$criteria->compare('caption',$this->caption,true);
$criteria->compare('alt_text',$this->alt_text,true);
$criteria->compare('tags',$this->tags,true);
$criteria->compare('sort_order',$this->sort_order);
$criteria->compare('created_dt',$this->created_dt,true);
$criteria->compare('lastupdate_dt',$this->lastupdate_dt,true);
return new CActiveDataProvider($this, array(
'criteria'=>$criteria,
));
}
/**
* Returns the static model of the specified AR class.
* Please note that you should have this exact method in all your CActiveRecord descendants!
* #param string $className active record class name.
* #return Photo the static model class
*/
public static function model($className=__CLASS__)
{
return parent::model($className);
}
}
I am getting this error: CDbCommand failed to execute the SQL statement: SQLSTATE[23000]: Integrity constraint violation: 1452 Cannot add or update a child row: a foreign key constraint fails (school2go2.tbl_album, CONSTRAINTtbl_album_ibfk_1FOREIGN KEY (owner_id) REFERENCEStbl_user(id) ON DELETE NO ACTION ON UPDATE NO ACTION). The SQL statement executed was: INSERT INTOtbl_album(name,tags,description,shareable,created_dt,owner_id) VALUES (:yp0, :yp1, :yp2, :yp3, NOW(), :yp4)
Please I am totally new to yii and even StackOverflow, pardon my inappropriate editing.I am still learning.

The error translates to: You are trying to insert an album without a corresponding owner.
Impossible to help more without knowing how you got that error.

Related

Retrieve the attributes passed to a factory within the definition method - Laravel 9

I've been trying to find a way to retrieve the attributes passed to a factory within the definition method but have no luck, I first attempted to access the $this->states property (within the definition method) which returns a closure and then attempted to retrieve the attributes from there but have had no luck with this.
I am currently using the factories below:-
<?php
namespace Database\Factories;
use App\Models\Developer;
use Illuminate\Database\Eloquent\Factories\Factory;
/**
* #extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Developer>
*/
class DeveloperFactory extends Factory
{
/**
* Specify the corresponding model for the factory
*
* #var string $model
*/
protected $model = Developer::class;
/**
* Define the model's default state.
*
* #return array<string, mixed>
*/
public function definition()
{
return [
'name' => $this->faker->firstName
];
}
public function configure()
{
$this->afterCreating(function (Developer $developer) {
User::factory()->create([
'userable_type' => $developer->getMorphClass(),
'userable_id' => $developer->id
]);
});
}
}
<?php
namespace Database\Factories;
use App\Models\User;
use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Support\Str;
class UserFactory extends Factory
{
/**
* The name of the factory's corresponding model.
*
* #var string
*/
protected $model = User::class;
/**
* Define the model's default state.
*
* #return array
*/
public function definition()
{
/**
* TODO: get any attributes that are passed into this factory
* e.g.userable_type, userable_id
*
* If these attributes are passed into the factory, stop the faker randomly generating a
* factory for a random user type and use the one passed into the factory
*/
$userableModel = (new $this->faker->userTypeModel)->factory()->create();
return [
'userable_type' => $userableModel->getMorphClass(),
'userable_id' => $userableModel->id,
'name' => $this->faker->name(),
'email' => $this->faker->unique()->safeEmail(),
'email_verified_at' => now(),
'password' => bcrypt('admin1234'), // password
'remember_token' => Str::random(10)
];
}
/**
* Indicate that the model's email address should be unverified.
*
* #return \Illuminate\Database\Eloquent\Factories\Factory
*/
public function unverified()
{
return $this->state(function (array $attributes) {
return [
'email_verified_at' => null,
];
});
}
}

I get this error when I try to register a new user. 'The department id must be an integer.'

I get this error when I try to register a new user: 'The department id must be an integer'. All the answers I'm receiving are helpful just that I get confused at times. So I've added more codes for clarification purposes. I have been battling around for some hours now. Here is the migration file.
Schema::create('departments', function (Blueprint $table) {
$table->bigIncrements('department_id');
$table->integer('department_name');
$table->integer('department_code')->unique();
$table->text('department_discription')->nullable();
$table->tinyInteger('department_status')->default(1);
$table->softDeletes();
$table->timestamps();
This is the DepartmentController codes
<?php
namespace App\Http\Controllers;
use App\Http\Requests\CreateDepartmentRequest;
use App\Http\Requests\UpdateDepartmentRequest;
use App\Repositories\DepartmentRepository;
use App\Http\Controllers\AppBaseController;
use Illuminate\Http\Request;
use Flash;
use Response;
class DepartmentController extends AppBaseController
{
/** #var DepartmentRepository */
private $departmentRepository;
public function __construct(DepartmentRepository $departmentRepo)
{
$this->departmentRepository = $departmentRepo;
}
/**
* Display a listing of the Department.
*
* #param Request $request
*
* #return Response
*/
public function index(Request $request)
{
$departments = $this->departmentRepository->all();
return view('departments.index')
->with('departments', $departments);
}
/**
* Show the form for creating a new Department.
*
* #return Response
*/
public function create()
{
return view('departments.create');
}
/**
* Store a newly created Department in storage.
*
* #param CreateDepartmentRequest $request
*
* #return Response
*/
public function store(CreateDepartmentRequest $request)
{
$input = $request->all();
$department = $this->departmentRepository->create($input);
Flash::success('Department saved successfully.');
return redirect(route('departments.index'));
}
/**
* Display the specified Department.
*
* #param int $id
*
* #return Response
*/
public function show($id)
{
$department = $this->departmentRepository->find($id);
if (empty($department)) {
Flash::error('Department not found');
return redirect(route('departments.index'));
}
return view('departments.show')->with('department', $department);
}
/**
* Show the form for editing the specified Department.
*
* #param int $id
*
* #return Response
*/
public function edit($id)
{
$department = $this->departmentRepository->find($id);
if (empty($department)) {
Flash::error('Department not found');
return redirect(route('departments.index'));
}
return view('departments.edit')->with('department', $department);
}
/**
* Update the specified Department in storage.
*
* #param int $id
* #param UpdateDepartmentRequest $request
*
* #return Response
*/
public function update($id, UpdateDepartmentRequest $request)
{
$department = $this->departmentRepository->find($id);
if (empty($department)) {
Flash::error('Department not found');
return redirect(route('departments.index'));
}
$department = $this->departmentRepository->update($request->all(), $id);
Flash::success('Department updated successfully.');
return redirect(route('departments.index'));
}
/**
* Remove the specified Department from storage.
*
* #param int $id
*
* #throws \Exception
*
* #return Response
*/
public function destroy($id)
{
$department = $this->departmentRepository->find($id);
if (empty($department)) {
Flash::error('Department not found');
return redirect(route('departments.index'));
}
$this->departmentRepository->delete($id);
Flash::success('Department deleted successfully.');
return redirect(route('departments.index'));
}
}
here is the department code
<?php
namespace App\Models;
use Eloquent as Model;
use Illuminate\Database\Eloquent\SoftDeletes;
/**
* Class Departments
* #package App\Models
* #version September 21, 2020, 4:31 pm UTC
*
* #property integer $department_name
* #property integer $department_code
* #property string $department_discription
* #property boolean $department_status
*/
class Departments extends Model
{
use SoftDeletes;
public $table = 'departments';
const CREATED_AT = 'created_at';
const UPDATED_AT = 'updated_at';
protected $dates = ['deleted_at'];
public $fillable = [
'department_name',
'department_code',
'department_discription',
'department_status'
];
/**
* The attributes that should be casted to native types.
*
* #var array
*/
protected $casts = [
'department_id' => 'integer',
'department_name' => 'integer',
'department_code' => 'integer',
'department_discription' => 'string',
'department_status' => 'boolean'
];
/**
* Validation rules
*
* #var array
*/
public static $rules = [
'department_name' => 'required|integer',
'department_code' => 'required|integer',
'department_discription' => 'nullable|string',
'department_status' => 'required|boolean',
'deleted_at' => 'nullable',
'created_at' => 'nullable',
'updated_at' => 'nullable'
];
}
in your migration, try make 'department_id' the primary key declaratively:
$table->primary('department_id');
then (like sta said in the comment) in your Department model:
protected $primaryKey = "department_id";
or change it's name to just 'id'
you should create a depatment like this:
\App\Models\Department::create([
'department_name' => 1,
'department_code' => 1,
'department_discription' => 'first department',
'department_status' => 1
]);
don't forget to add columns name to fillable variable in your Department model
If I understand your question, you are going to need to change your department_id field in the db.
Create a new migration and for your department_id key, set it like this.
$table->unsignedBigInteger('department_id')->autoIncrement();
That should take care of your issue. What it will do is maintain the integrity of your db in the event that you need to add a relationship because it will create that field the same type as the id on other tables (unsignedBigInteger), but it will also autoIncrement the field.

Altering table after generating CRUD code gives error in yii

I have a table with 2 fields and generated CRUD which is working well. I added to 2 more fields to that table and applied required changes in model, controller and view. But yii shows error for the newly added fields saying that those attributes are not defined.
This is my model code:
class Product extends CActiveRecord
{
public function tableName()
{
return 'product';
}
/**
* #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('title, subTitle, image, shortDesc, longDesc, seo_title, focus_keywords, meta_desc, meta_url, created, updated', 'required'),
array('status', 'numerical', 'integerOnly'=>true),
array('title, subTitle, image', 'length', 'max'=>128),
array('seo_title, focus_keywords, meta_desc, meta_url', 'length', 'max'=>255),
// The following rule is used by search().
// #todo Please remove those attributes that should not be searched.
array('id, title, subTitle, image, shortDesc, longDesc, status, seo_title, focus_keywords, meta_desc, meta_url, created, updated', '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(
'id' => 'ID',
'title' => 'Title',
'subTitle' => 'Sub Title',
'image' => 'Image',
'shortDesc' => 'Short Desc',
'longDesc' => 'Long Desc',
'status' => 'Status',
'seo_title' => 'Seo Title',
'focus_keywords' => 'Focus Keywords',
'meta_desc' => 'Meta Desc',
'meta_url' => 'Meta Url',
'created' => 'Created',
'updated' => 'Updated',
);
}
/**
* Retrieves a list of models based on the current search/filter conditions.
*
* Typical usecase:
* - Initialize the model fields with values from filter form.
* - Execute this method to get CActiveDataProvider instance which will filter
* models according to data in model fields.
* - Pass data provider to CGridView, CListView or any similar widget.
*
* #return CActiveDataProvider the data provider that can return the models
* based on the search/filter conditions.
*/
public function search()
{
// #todo Please modify the following code to remove attributes that should not be searched.
$criteria=new CDbCriteria;
$criteria->compare('id',$this->id);
$criteria->compare('title',$this->title,true);
$criteria->compare('subTitle',$this->subTitle,true);
$criteria->compare('image',$this->image,true);
$criteria->compare('shortDesc',$this->shortDesc,true);
$criteria->compare('longDesc',$this->longDesc,true);
$criteria->compare('status',$this->status);
$criteria->compare('seo_title',$this->seo_title,true);
$criteria->compare('focus_keywords',$this->focus_keywords,true);
$criteria->compare('meta_desc',$this->meta_desc,true);
$criteria->compare('meta_url',$this->meta_url,true);
$criteria->compare('created',$this->created,true);
$criteria->compare('updated',$this->updated,true);
return new CActiveDataProvider($this, array(
'criteria'=>$criteria,
));
}
/**
* Returns the static model of the specified AR class.
* Please note that you should have this exact method in all your CActiveRecord descendants!
* #param string $className active record class name.
* #return Product the static model class
*/
public static function model($className=__CLASS__)
{
return parent::model($className);
}
}
Clear Yii cache (protected/runtime)

how to join 3 models to display data in a cgridview using yii

i am newbie in yii framework. I have 3 tables table A,table B,table C. table A and table B are related with primary and foreign key relationship.same way table B and table C are linked with priamary and foreign key relationshiop..i want to display,filter data in cgridview of admin page..using a yii fra
updated:
i have 3 models.subscriber.php,assignment.php,groups.php
i want to display attributes from 3 models and display them in cgridview of subscriber.php???
subscriber.php..........
/**
* This is the model class for table "users_phone_numbers".
*
* The followings are the available columns in table 'users_phone_numbers':
* #property integer $id
* #property string $name
* #property string $phone_number
* #property integer $created_user
* #property string $created_date
* #property integer $modified_user
* #property string $modified_date
* #property integer $status
* #property string $message_type
* #property string $birthdate
* #property string $email
*
* The followings are the available model relations:
* #property PhoneNumberGroupAssignment[] $phoneNumberGroupAssignments
*/
class subscriber extends CActiveRecord
{
//public $group_search; //for searching and displaying in cgridview
/**
* Returns the static model of the specified AR class.
* #param string $className active record class name.
* #return subscriber 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 'users_phone_numbers';
}
/**
* #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('phone_number, created_user, created_date, birthdate, email', 'required'),
array('created_user, modified_user, status', 'numerical', 'integerOnly'=>true),
array('name, phone_number', 'length', 'max'=>100),
array('message_type', 'length', 'max'=>20),
array('email', 'length', 'max'=>150),
array('modified_date', 'safe'),
// The following rule is used by search().
// Please remove those attributes that should not be searched.
array('id, name, phone_number, created_user, created_date, modified_user, modified_date, status, message_type, birthdate, email ', 'safe', 'on'=>'search'),//add above defined variable.
);
}
/**
* #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(
'phoneNumberGroupAssignments' => array(self::HAS_MANY, 'Assignment', 'phone_number_id'),
//'postCount' => array(self::STAT, 'assignment', 'phone_number_id'),
);
}
/**
* #return array customized attribute labels (name=>label)
*/
public function attributeLabels()
{
return array(
'id' => 'ID',
'name' => 'Name',
'phone_number' => 'Phone Number',
'created_user' => 'Created User',
'created_date' => 'Created Date',
'modified_user' => 'Modified User',
'modified_date' => 'Modified Date',
'status' => 'Status',
'message_type' => 'Message Type',
'birthdate' => 'Birthdate',
'email' => 'Email',
);
}
/**
* 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->with = array( 'phoneNumberGroupAssignments' ); //new
$criteria->compare('id',$this->id);
$criteria->compare('name',$this->name,true);
$criteria->compare('phone_number',$this->phone_number,true);
$criteria->compare('created_user',$this->created_user);
$criteria->compare('created_date',$this->created_date,true);
$criteria->compare('modified_user',$this->modified_user);
$criteria->compare('modified_date',$this->modified_date,true);
$criteria->compare('status',$this->status);
$criteria->compare('message_type',$this->message_type,true);
$criteria->compare('birthdate',$this->birthdate,true);
$criteria->compare('email',$this->email,true);
//$criteria->compare( 'phoneNumberGroupAssignments.group_id', $this->group_search, true );
return new CActiveDataProvider($this, array('criteria'=>$criteria,
/*'sort'=>array(
'attributes'=>array(
'group_search'=>array(
'asc'=>'phoneNumberGroupAssignments.group_id',
'desc'=>'phoneNumberGroupAssignments.group_id DESC',
),
),
),
*/
));
}
}
2nd assignment.php
/**
* This is the model class for table "phone_number_group_assignment".
*
* The followings are the available columns in table 'phone_number_group_assignment':
* #property integer $id
* #property integer $phone_number_id
* #property integer $group_id
* #property integer $created_user
* #property string $created_date
* #property integer $modified_user
* #property string $modified_date
*
* The followings are the available model relations:
* #property UsersPhoneNumbers $phoneNumber
*/
class assignment extends CActiveRecord
{
/**
* Returns the static model of the specified AR class.
* #param string $className active record class name.
* #return assignment 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 'phone_number_group_assignment';
}
/**
* #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('phone_number_id, group_id, created_date', 'required'),
array('phone_number_id, group_id, created_user, modified_user', 'numerical', 'integerOnly'=>true),
array('modified_date', 'safe'),
// The following rule is used by search().
// Please remove those attributes that should not be searched.
array('id, phone_number_id, group_id, created_user, created_date, modified_user, modified_date', '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(
'phoneNumber' => array(self::BELONGS_TO, 'Subscriber', 'phone_number_id'),
);
}
/**
* #return array customized attribute labels (name=>label)
*/
public function attributeLabels()
{
return array(
'id' => 'ID',
'phone_number_id' => 'Phone Number',
'group_id' => 'Group',
'created_user' => 'Created User',
'created_date' => 'Created Date',
'modified_user' => 'Modified User',
'modified_date' => 'Modified Date',
);
}
/**
* 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('id',$this->id);
$criteria->compare('phone_number_id',$this->phone_number_id);
$criteria->compare('group_id',$this->group_id);
$criteria->compare('created_user',$this->created_user);
$criteria->compare('created_date',$this->created_date,true);
$criteria->compare('modified_user',$this->modified_user);
$criteria->compare('modified_date',$this->modified_date,true);
return new CActiveDataProvider($this, array(
'criteria'=>$criteria,
));
}
}
3rd one :
groups.php
/**
* This is the model class for table "client_groups".
*
* The followings are the available columns in table 'client_groups':
* #property integer $id
* #property integer $client_id
* #property string $title
* #property string $keywords
* #property integer $status
* #property integer $created_user
* #property string $created_date
* #property integer $modified_user
* #property string $modified_date
* #property integer $is_default
* #property integer $is_special_group
* #property string $back_office_no
* #property string $special_group_sms_text
* #property string $text_sms_office
* #property string $day_delay_1
* #property string $subscription_sms_1
* #property string $day_delay_2
* #property string $subscription_sms_2
* #property string $day_delay_3
* #property string $subscription_sms_3
* #property string $campaign_sms
* #property string $delay_time_1
* #property string $delay_time_2
* #property string $delay_time_3
* #property integer $msg_counter
* #property integer $msg_counter_start_num
* #property integer $add_expiry
* #property integer $add_days
* #property integer $phone_number_id
* #property integer $ar_type
* #property string $email
*
* The followings are the available model relations:
* #property ClientInformation $client
*/
class Groups extends CActiveRecord
{
/**
* Returns the static model of the specified AR class.
* #param string $className active record class name.
* #return Groups 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 'client_groups';
}
/**
* #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('client_id, created_user, created_date, msg_counter, add_expiry, add_days, phone_number_id, ar_type, email', 'required'),
array('client_id, status, created_user, modified_user, is_default, is_special_group, msg_counter, msg_counter_start_num, add_expiry, add_days, phone_number_id, ar_type', 'numerical', 'integerOnly'=>true),
array('title', 'length', 'max'=>250),
array('keywords', 'length', 'max'=>255),
array('back_office_no', 'length', 'max'=>50),
array('day_delay_1, day_delay_2, day_delay_3', 'length', 'max'=>3),
array('subscription_sms_1, subscription_sms_2, subscription_sms_3, campaign_sms, email', 'length', 'max'=>200),
array('modified_date, special_group_sms_text, text_sms_office, delay_time_1, delay_time_2, delay_time_3', 'safe'),
// The following rule is used by search().
// Please remove those attributes that should not be searched.
array('id, client_id, title, keywords, status, created_user, created_date, modified_user, modified_date, is_default, is_special_group, back_office_no, special_group_sms_text, text_sms_office, day_delay_1, subscription_sms_1, day_delay_2, subscription_sms_2, day_delay_3, subscription_sms_3, campaign_sms, delay_time_1, delay_time_2, delay_time_3, msg_counter, msg_counter_start_num, add_expiry, add_days, phone_number_id, ar_type, email', '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(
'client' => array(self::BELONGS_TO, 'ClientInformation', 'client_id'),
);
}
/**
* #return array customized attribute labels (name=>label)
*/
public function attributeLabels()
{
return array(
'id' => 'ID',
'client_id' => 'Client',
'title' => 'Title',
'keywords' => 'Keywords',
'status' => 'Status',
'created_user' => 'Created User',
'created_date' => 'Created Date',
'modified_user' => 'Modified User',
'modified_date' => 'Modified Date',
'is_default' => 'Is Default',
'is_special_group' => 'Is Special Group',
'back_office_no' => 'Back Office No',
'special_group_sms_text' => 'Special Group Sms Text',
'text_sms_office' => 'Text Sms Office',
'day_delay_1' => 'Day Delay 1',
'subscription_sms_1' => 'Subscription Sms 1',
'day_delay_2' => 'Day Delay 2',
'subscription_sms_2' => 'Subscription Sms 2',
'day_delay_3' => 'Day Delay 3',
'subscription_sms_3' => 'Subscription Sms 3',
'campaign_sms' => 'Campaign Sms',
'delay_time_1' => 'Delay Time 1',
'delay_time_2' => 'Delay Time 2',
'delay_time_3' => 'Delay Time 3',
'msg_counter' => 'Msg Counter',
'msg_counter_start_num' => 'Msg Counter Start Num',
'add_expiry' => 'Add Expiry',
'add_days' => 'Add Days',
'phone_number_id' => 'Phone Number',
'ar_type' => 'Ar Type',
'email' => 'Email',
);
}
/**
* 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('id',$this->id);
$criteria->compare('client_id',$this->client_id);
$criteria->compare('title',$this->title,true);
$criteria->compare('keywords',$this->keywords,true);
$criteria->compare('status',$this->status);
$criteria->compare('created_user',$this->created_user);
$criteria->compare('created_date',$this->created_date,true);
$criteria->compare('modified_user',$this->modified_user);
$criteria->compare('modified_date',$this->modified_date,true);
$criteria->compare('is_default',$this->is_default);
$criteria->compare('is_special_group',$this->is_special_group);
$criteria->compare('back_office_no',$this->back_office_no,true);
$criteria->compare('special_group_sms_text',$this->special_group_sms_text,true);
$criteria->compare('text_sms_office',$this->text_sms_office,true);
$criteria->compare('day_delay_1',$this->day_delay_1,true);
$criteria->compare('subscription_sms_1',$this->subscription_sms_1,true);
$criteria->compare('day_delay_2',$this->day_delay_2,true);
$criteria->compare('subscription_sms_2',$this->subscription_sms_2,true);
$criteria->compare('day_delay_3',$this->day_delay_3,true);
$criteria->compare('subscription_sms_3',$this->subscription_sms_3,true);
$criteria->compare('campaign_sms',$this->campaign_sms,true);
$criteria->compare('delay_time_1',$this->delay_time_1,true);
$criteria->compare('delay_time_2',$this->delay_time_2,true);
$criteria->compare('delay_time_3',$this->delay_time_3,true);
$criteria->compare('msg_counter',$this->msg_counter);
$criteria->compare('msg_counter_start_num',$this->msg_counter_start_num);
$criteria->compare('add_expiry',$this->add_expiry);
$criteria->compare('add_days',$this->add_days);
$criteria->compare('phone_number_id',$this->phone_number_id);
$criteria->compare('ar_type',$this->ar_type);
$criteria->compare('email',$this->email,true);
return new CActiveDataProvider($this, array(
'criteria'=>$criteria,
));
}
}
current cgrid view is accessing data from two models,assignemnt and subscriber but not from groups. and it givers error rying to get property of non-object
C:\wamp\www\yii\framework\base\CComponent.php(607) : eval()'d code(1)
..so plz check this for 2 and then for 3 models? urgent help needed.thanks
From the admin view for table A you should be able to access the other values by listing them like this in the column definition:
'columns'=>array(
array('name'=>'column heading 1','value'=>'$data->modelB_nameinA->col_name1'),
array('name'=>'column heading 2','value'=>'$data->modelB_nameinA->C->col_name2'),
For filtering on these values you need to be able to access them in the modelA->search() function. The simplest way I have found to do that is to explicitly set a public value in A for each col_name you want to display from B and C. You need to also include them in the safe search statement in modelA->rules() and for simplicity also in the modelA->attributeLabels(). You might also have to include C in the relations of A, so the modelA class would look something like this:
class A extends CActiveRecord
{
/**
* #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(
...
// Please remove those attributes that should not be searched.
array('Col1_fromA, Col2_fromA, Col1_fromB, Col1_fromC', 'safe', 'on'=>'search'),
);
}
/**
* Put here the names of the columns from B and C that you are wanting to filter on
*/
public $Col1_fromB;
public $Col1_fromC;
/**
* #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(
'modelB_nameinA' => array(self::HAS_MANY, 'B', 'B_id'),
'modelC_nameinA' => array(self::HAS_MANY, 'C', array('C_id'=>'id'),'through'=>'B'),
);
}
/**
* #return array customized attribute labels (name=>label)
*/
public function attributeLabels()
{
return array(
'Col1_fromA' => 'Fancy name for Col1_fromA',
'Col2_fromA' => 'Fancy name for Col2_fromA',
'Col1_fromB' => 'Fancy name for Col1_fromB',
'Col1_fromC' => 'Fancy name for Col1_fromC',
);
}
/**
* 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;
// this is so those two tables are included in the SQL generated:
$criteria->with = array( 'B', 'C' );
$criteria->together=true;
$criteria->compare('Col1_fromA',$this->Col1_fromA,true);
$criteria->compare('Col2_fromA',$this->Col2_fromA,true);
$criteria->compare('modelB_nameinA.Col1', $this->Col1_fromB,true);
$criteria->compare('modelC_nameinA.Col1', $this->Col1_fromC,true);
return new CActiveDataProvider($this, array(
'criteria'=>$criteria,
));
}
...
One advantage of this is that you can now use the Col1_fromB and Col1_fromC as the name value in the columns definition in cgridview and you will get the fancy names you entered in the definition of modelA as column headings.
You need to define relations in table A and B to get model C from table A.
Table A relations:
public function relations() {
return array(
'tableB'=>array(self::HAS_ONE, 'TableB', 'tablea_id'),
);
}
Table B relations:
public function relations() {
return array(
'tableC'=>array(self::HAS_ONE, 'TableC', 'tableb_id'),
);
}
So you can acces tableB and tableC model, related with your tableA:
$modelB = $tableA->tableB;
$modelC = $tableA->tableB->tableC;
You can read here about relational active record.
In your controller action get the model:
public function actionGrid() {
$model = new ModelA('search');
$model->unsetAttributes();
$this->render('view', array('model'=>$model));
}
And view code with CGridView:
$this->widget('zii.widgets.grid.CGridView', array(
'id' => 'grid',
'dataProvider'=>$model->search(),
'filter' => $model,
'ajaxUpdate'=>false,
'selectableRows'=>'10',
'columns'=>array(
array(
'id'=>'checkBoxId',
'class'=>'CCheckBoxColumn',
),
array(
'class'=>'CDataColumn',
'name'=>'modelA_attrib1',
'value'=>'$data->attrib1',
'sortable'=>true,
'filter'=>true,
),
array(
'class'=>'CDataColumn',
'name'=>'modelB_attrib1',
'value'=>'$data->modelB->attrib1',
'sortable'=>true,
'filter'=>true,
),
array(
'class'=>'CDataColumn',
'name'=>'modelC_attrib1',
'value'=>'$data->modelB->modelC->attrib1',
'sortable'=>true,
'filter'=>true,
),
...
Update:
If I properly understood, you have MANY_TO_MANY relation within your users_phone_numbers and client_groups tables (group could be related with many phone numbers, and number refer to many groups).
So phone_number_group_assignment (commonly referred to as phone_number_group) must contain two primary keys:
* #property integer $phone_number_id
* #property integer $group_id
And relations of subscriber:
public function relations()
{
return array(
'groups' => array(self::MANY_MANY, 'Groups', 'phone_number_group_assignment(phone_number_id, group_id)'),
);
}
Relations for groups:
public function relations()
{
return array(
'phone_numbers' => array(self::MANY_MANY, 'Subscriber', 'phone_number_group_assignment(group_id, phone_number_id)'),
);
}
So you can access groups from subscriber: $subscriber->groups
make a view in database and put all your needed columns after joins operations and then make the model.
I use this always
As #user181452 said, create a View and then generate a model. Other way would be that in your target model, bind each new attribute with a public variable in the model
class NewModel {
public $new_attribute;
}
Then you would be able to access to it from views. You have to chose the cleanest way for your project, 'cause create a view is better if you have a complex JOIN.

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.