ORM Self-referenced entity not persisting into database properly - database

ive been trying to figure this out for 2 hours now and i cant seem to understand what went wrong.
I am using Symfony2 and FOSUserBundle.
I created a User entity which extends FOSUserBundle's BaseUser class. Within this User entity, i have 3 variables, id, my_mentors and my_mentees. More details are below:
class User extends BaseUser
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\ManyToMany(targetEntity="User", mappedBy="my_mentees")
*/
protected $my_mentors;
/**
* #ORM\ManyToMany(targetEntity="User", inversedBy="my_mentors")
* #ORM\JoinTable(name="mentor_and_mentee_relationship",
* joinColumns={#ORM\JoinColumn(name="user_id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="mentors_or_mentees_user_id", referencedColumnName="id")}
* )
*/
protected $my_mentees;
public function __construct()
{
parent::__construct();
$this->my_mentors = new ArrayCollection();
$this->my_mentees = new ArrayCollection();
}
public function __toString()
{
return $this->getUsername();
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Add my_mentors
*
* #param Fitness\FitBundle\Entity\User $myMentors
*/
public function addUser(\Fitness\FitBundle\Entity\User $myMentors)
{
$this->my_mentors[] = $myMentors;
}
/**
* Get my_mentors
*
* #return Doctrine\Common\Collections\Collection
*/
public function getMyMentors()
{
return $this->my_mentors;
}
/**
* Get my_mentees
*
* #return Doctrine\Common\Collections\Collection
*/
public function getMyMentees()
{
return $this->my_mentees;
}
}
I created the self reference because a Mentee(which is a User) will subscribe to a Mentor(which is also a User). I tried to do this using the following function:
public function subscribeAction($menteeID, $mentorID)
{
$em = $this->getDoctrine()
->getEntityManager();
$mentor = $em->getRepository('TestBundle:User')
->find($mentorID);
$mentee = $em->getRepository('TestBundle:User')
->find($menteeID);
$currentMentors = $mentee->getMyMentors();
if ($currentMentors->contains($mentor))
$this->get('session')->setFlash('subscribe-notice', 'You have already signed up to this mentor!');
else
{
$mentee->setIsMentor(false);
$mentee->addUser($mentor);
$mentor->addUser($mentee);
$em->persist($mentee);
$em->persist($mentor);
$em->flush();
$this->get('session')->setFlash('subscribe-notice', 'Subscription succesful!');
}
return $this->redirect($this->generateUrl('TestBundle_testpage', array('id' => $mentor->getMentorProfile()->getId()) ));
}
The problem here is that when i check the database, it does not persist the data. The mentor-mentee relationship information is not stored in the table "mentor_and_mentee_relationship" as declared by the annotation.
I persisted both $mentor and $mentee in an attempt to get it to work, but apparently it doesnt.
Could my ORM annotation be declared wrongly?

You are using the same function (addUser) to add a mentor and to add a mentee. This is wrong. First you need two different setters in your entity (I changed the name of addUser to make it clear)
/**
* Add my_mentors
*
* #param Fitness\FitBundle\Entity\User $myMentors
*/
public function addMentor(\Fitness\FitBundle\Entity\User $myMentors)
{
$this->my_mentors[] = $myMentors;
}
/**
* Add my_mentees
*
* #param Fitness\FitBundle\Entity\User $myMentees
*/
public function addMentee(\Fitness\FitBundle\Entity\User $myMentees)
{
$this->my_mentees[] = $myMentees;
}
Then in your controller do:
$mentee->addMentor($mentor);
$mentor->addMentee($mentee);

Related

Why there is 2 primary keys in table (Sentinel framework database)?

i included SENTINEL framework with implemented Sentinel migration into my LARAVEL project. Lot of things are clear to me but i can't understand why there is 2 primary keys in Role_users table, because i learned that for connection between 2 tables we need primary key and foreign key which is not a case here (role_users table). If someone knows explanation It would mean a lot to me.
my Database Scheme
Php my admin scheme
migration_cartalyst_sentinel
<?php
/**
* Part of the Sentinel package.
*
* NOTICE OF LICENSE
*
* Licensed under the 3-clause BSD License.
*
* This source file is subject to the 3-clause BSD License that is
* bundled with this package in the LICENSE file.
*
* #package Sentinel
* #version 2.0.17
* #author Cartalyst LLC
* #license BSD License (3-clause)
* #copyright (c) 2011-2017, Cartalyst LLC
* #link http://cartalyst.com
*/
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
class MigrationCartalystSentinel extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('activations', function (Blueprint $table) {
$table->increments('id');
$table->integer('user_id')->unsigned();
$table->string('code');
$table->boolean('completed')->default(0);
$table->timestamp('completed_at')->nullable();
$table->timestamps();
$table->engine = 'InnoDB';
});
Schema::create('persistences', function (Blueprint $table) {
$table->increments('id');
$table->integer('user_id')->unsigned();
$table->string('code');
$table->timestamps();
$table->engine = 'InnoDB';
$table->unique('code');
});
Schema::create('reminders', function (Blueprint $table) {
$table->increments('id');
$table->integer('user_id')->unsigned();
$table->string('code');
$table->boolean('completed')->default(0);
$table->timestamp('completed_at')->nullable();
$table->timestamps();
$table->engine = 'InnoDB';
});
Schema::create('roles', function (Blueprint $table) {
$table->increments('id');
$table->string('slug');
$table->string('name');
$table->text('permissions')->nullable();
$table->timestamps();
$table->engine = 'InnoDB';
$table->unique('slug');
});
Schema::create('role_users', function (Blueprint $table) {
$table->integer('user_id')->unsigned();
$table->integer('role_id')->unsigned();
$table->nullableTimestamps();
$table->engine = 'InnoDB';
$table->primary(['user_id', 'role_id']);
});
Schema::create('throttle', function (Blueprint $table) {
$table->increments('id');
$table->integer('user_id')->unsigned()->nullable();
$table->string('type');
$table->string('ip')->nullable();
$table->timestamps();
$table->engine = 'InnoDB';
$table->index('user_id');
});
Schema::create('users', function (Blueprint $table) {
$table->increments('id');
$table->string('email');
$table->string('password');
$table->text('permissions')->nullable();
$table->timestamp('last_login')->nullable();
$table->string('first_name')->nullable();
$table->string('last_name')->nullable();
$table->timestamps();
$table->engine = 'InnoDB';
$table->unique('email');
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::drop('activations');
Schema::drop('persistences');
Schema::drop('reminders');
Schema::drop('roles');
Schema::drop('role_users');
Schema::drop('throttle');
Schema::drop('users');
}
}
EloquentUser
<?php
/**
* Part of the Sentinel package.
*
* NOTICE OF LICENSE
*
* Licensed under the 3-clause BSD License.
*
* This source file is subject to the 3-clause BSD License that is
* bundled with this package in the LICENSE file.
*
* #package Sentinel
* #version 2.0.17
* #author Cartalyst LLC
* #license BSD License (3-clause)
* #copyright (c) 2011-2017, Cartalyst LLC
* #link http://cartalyst.com
*/
namespace Cartalyst\Sentinel\Users;
use Cartalyst\Sentinel\Permissions\PermissibleInterface;
use Cartalyst\Sentinel\Permissions\PermissibleTrait;
use Cartalyst\Sentinel\Persistences\PersistableInterface;
use Cartalyst\Sentinel\Roles\RoleableInterface;
use Cartalyst\Sentinel\Roles\RoleInterface;
use Illuminate\Database\Eloquent\Model;
class EloquentUser extends Model implements RoleableInterface, PermissibleInterface, PersistableInterface, UserInterface
{
use PermissibleTrait;
/**
* {#inheritDoc}
*/
protected $table = 'users';
/**
* {#inheritDoc}
*/
protected $fillable = [
'email',
'password',
'last_name',
'first_name',
'permissions',
];
/**
* {#inheritDoc}
*/
protected $hidden = [
'password',
];
/**
* {#inheritDoc}
*/
protected $persistableKey = 'user_id';
/**
* {#inheritDoc}
*/
protected $persistableRelationship = 'persistences';
/**
* Array of login column names.
*
* #var array
*/
protected $loginNames = ['email'];
/**
* The Eloquent roles model name.
*
* #var string
*/
protected static $rolesModel = 'Cartalyst\Sentinel\Roles\EloquentRole';
/**
* The Eloquent persistences model name.
*
* #var string
*/
protected static $persistencesModel = 'Cartalyst\Sentinel\Persistences\EloquentPersistence';
/**
* The Eloquent activations model name.
*
* #var string
*/
protected static $activationsModel = 'Cartalyst\Sentinel\Activations\EloquentActivation';
/**
* The Eloquent reminders model name.
*
* #var string
*/
protected static $remindersModel = 'Cartalyst\Sentinel\Reminders\EloquentReminder';
/**
* The Eloquent throttling model name.
*
* #var string
*/
protected static $throttlingModel = 'Cartalyst\Sentinel\Throttling\EloquentThrottle';
/**
* Returns an array of login column names.
*
* #return array
*/
public function getLoginNames()
{
return $this->loginNames;
}
/**
* Returns the roles relationship.
*
* #return \Illuminate\Database\Eloquent\Relations\BelongsToMany
*/
public function roles()
{
return $this->belongsToMany(static::$rolesModel, 'role_users', 'user_id', 'role_id')->withTimestamps();
}
/**
* Returns the persistences relationship.
*
* #return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function persistences()
{
return $this->hasMany(static::$persistencesModel, 'user_id');
}
/**
* Returns the activations relationship.
*
* #return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function activations()
{
return $this->hasMany(static::$activationsModel, 'user_id');
}
/**
* Returns the reminders relationship.
*
* #return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function reminders()
{
return $this->hasMany(static::$remindersModel, 'user_id');
}
/**
* Returns the throttle relationship.
*
* #return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function throttle()
{
return $this->hasMany(static::$throttlingModel, 'user_id');
}
/**
* Get mutator for the "permissions" attribute.
*
* #param mixed $permissions
* #return array
*/
public function getPermissionsAttribute($permissions)
{
return $permissions ? json_decode($permissions, true) : [];
}
/**
* Set mutator for the "permissions" attribute.
*
* #param mixed $permissions
* #return void
*/
public function setPermissionsAttribute(array $permissions)
{
$this->attributes['permissions'] = $permissions ? json_encode($permissions) : '';
}
/**
* {#inheritDoc}
*/
public function getRoles()
{
return $this->roles;
}
/**
* {#inheritDoc}
*/
public function inRole($role)
{
if ($role instanceof RoleInterface) {
$roleId = $role->getRoleId();
}
foreach ($this->roles as $instance) {
if ($role instanceof RoleInterface) {
if ($instance->getRoleId() === $roleId) {
return true;
}
} else {
if ($instance->getRoleId() == $role || $instance->getRoleSlug() == $role) {
return true;
}
}
}
return false;
}
/**
* {#inheritDoc}
*/
public function generatePersistenceCode()
{
return str_random(32);
}
/**
* {#inheritDoc}
*/
public function getUserId()
{
return $this->getKey();
}
/**
* {#inheritDoc}
*/
public function getPersistableId()
{
return $this->getKey();
}
/**
* {#inheritDoc}
*/
public function getPersistableKey()
{
return $this->persistableKey;
}
/**
* {#inheritDoc}
*/
public function setPersistableKey($key)
{
$this->persistableKey = $key;
}
/**
* {#inheritDoc}
*/
public function setPersistableRelationship($persistableRelationship)
{
$this->persistableRelationship = $persistableRelationship;
}
/**
* {#inheritDoc}
*/
public function getPersistableRelationship()
{
return $this->persistableRelationship;
}
/**
* {#inheritDoc}
*/
public function getUserLogin()
{
return $this->getAttribute($this->getUserLoginName());
}
/**
* {#inheritDoc}
*/
public function getUserLoginName()
{
return reset($this->loginNames);
}
/**
* {#inheritDoc}
*/
public function getUserPassword()
{
return $this->password;
}
/**
* Returns the roles model.
*
* #return string
*/
public static function getRolesModel()
{
return static::$rolesModel;
}
/**
* Sets the roles model.
*
* #param string $rolesModel
* #return void
*/
public static function setRolesModel($rolesModel)
{
static::$rolesModel = $rolesModel;
}
/**
* Returns the persistences model.
*
* #return string
*/
public static function getPersistencesModel()
{
return static::$persistencesModel;
}
/**
* Sets the persistences model.
*
* #param string $persistencesModel
* #return void
*/
public static function setPersistencesModel($persistencesModel)
{
static::$persistencesModel = $persistencesModel;
}
/**
* Returns the activations model.
*
* #return string
*/
public static function getActivationsModel()
{
return static::$activationsModel;
}
/**
* Sets the activations model.
*
* #param string $activationsModel
* #return void
*/
public static function setActivationsModel($activationsModel)
{
static::$activationsModel = $activationsModel;
}
/**
* Returns the reminders model.
*
* #return string
*/
public static function getRemindersModel()
{
return static::$remindersModel;
}
/**
* Sets the reminders model.
*
* #param string $remindersModel
* #return void
*/
public static function setRemindersModel($remindersModel)
{
static::$remindersModel = $remindersModel;
}
/**
* Returns the throttling model.
*
* #return string
*/
public static function getThrottlingModel()
{
return static::$throttlingModel;
}
/**
* Sets the throttling model.
*
* #param string $throttlingModel
* #return void
*/
public static function setThrottlingModel($throttlingModel)
{
static::$throttlingModel = $throttlingModel;
}
/**
* {#inheritDoc}
*/
public function delete()
{
$isSoftDeleted = array_key_exists('Illuminate\Database\Eloquent\SoftDeletes', class_uses($this));
if ($this->exists && ! $isSoftDeleted) {
$this->activations()->delete();
$this->persistences()->delete();
$this->reminders()->delete();
$this->roles()->detach();
$this->throttle()->delete();
}
return parent::delete();
}
/**
* Dynamically pass missing methods to the user.
*
* #param string $method
* #param array $parameters
* #return mixed
*/
public function __call($method, $parameters)
{
$methods = ['hasAccess', 'hasAnyAccess'];
if (in_array($method, $methods)) {
$permissions = $this->getPermissionsInstance();
return call_user_func_array([$permissions, $method], $parameters);
}
return parent::__call($method, $parameters);
}
/**
* Creates a permissions object.
*
* #return \Cartalyst\Sentinel\Permissions\PermissionsInterface
*/
protected function createPermissions()
{
$userPermissions = $this->permissions;
$rolePermissions = [];
foreach ($this->roles as $role) {
$rolePermissions[] = $role->permissions;
}
return new static::$permissionsClass($userPermissions, $rolePermissions);
}
}
Role_users is used as a pivot table in this case; it's the intermediate table in the many-to-many relationship between Users and Roles. A User can belong to many Roles, and a Role can belong to many Users.
The composite primary key on Role_users ensures that no User will have the same Role twice, and vice versa. The primary key is a unique combination of the user_id and role_id.

Symfony2 Association class form

This is my first Symfony project, and I can't figure out how to solve my problem.
Basically, i'm trying to make an invoice using a form.
I have a "Facturation" (ie invoice) Entity, a "TypeOfService" Entity, and a "Service" Entity (the sole attribute of which is the quantity of the type of service needed for the invoice) that acts as an association class.
I'd like to dynamically add "New Service" fields to my FacturationType form using Javascript (probably AngularJS). So I have to create N new Service entities that each associate with both my Facturation entity and an existing TypeOfService entity.
Here's my Facturation entity:
use Doctrine\ORM\Mapping AS ORM;
/**
* Facturation
*
* #ORM\Table(name="facturation")
* #ORM\Entity
*/
class Facturation
{
...
/**
* #ORM\OneToMany(targetEntity="Service", mappedBy="facturation")
*/
private $service;
/**
* Add service
*
* #param \AppBundle\Entity\Service $service
* #return Facturation
*/
public function addService(\AppBundle\Entity\Service $service)
{
$this->service[] = $service;
return $this;
}
/**
* Remove service
*
* #param \AppBundle\Entity\Service $service
*/
public function removeService(\AppBundle\Entity\Service $service)
{
$this->service->removeElement($service);
}
/**
* Get service
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getService()
{
return $this->service;
}
}
Then Service:
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping AS ORM;
/**
* Service
*
* #ORM\Table(name="service")
* #ORM\Entity
*/
class Service
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\Column(type="integer", nullable=true)
*/
private $quantity;
/**
* #ORM\ManyToOne(targetEntity="TypeOfService", inversedBy="service")
* #ORM\JoinColumn(name="type_of_service_id", referencedColumnName="id")
*/
private $typeOfService;
/**
* #ORM\ManyToOne(targetEntity="Facturation", inversedBy="service")
* #ORM\JoinColumn(name="facturation_id", referencedColumnName="id")
*/
private $facturation;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set quantity
*
* #param integer $quantity
* #return Service
*/
public function setQuantity($quantity)
{
$this->quantity = $quantity;
return $this;
}
/**
* Get quantity
*
* #return integer
*/
public function getQuantity()
{
return $this->quantity;
}
/**
* Set typeOfService
*
* #param \AppBundle\Entity\TypeOfService $typeOfService
* #return Service
*/
public function setTypeOfService(\AppBundle\Entity\TypeOfService $typeOfService = null)
{
$this->typeOfService = $typeOfService;
return $this;
}
/**
* Get typeOfService
*
* #return \AppBundle\Entity\TypeOfService
*/
public function getTypeOfService()
{
return $this->typeOfService;
}
/**
* Set facturation
*
* #param \AppBundle\Entity\Facturation $facturation
* #return Service
*/
public function setFacturation(\AppBundle\Entity\Facturation $facturation = null)
{
$this->facturation = $facturation;
return $this;
}
/**
* Get facturation
*
* #return \AppBundle\Entity\Facturation
*/
public function getFacturation()
{
return $this->facturation;
}
}
And finally TypeOfService
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping AS ORM;
/**
* TypeOfService
*
* #ORM\Table(name="type_of_service")
* #ORM\Entity
*/
class TypeOfService
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\Column(nullable=true)
*/
private $name;
/**
* #ORM\Column(type="integer", nullable=true)
*/
private $pricePerUnit;
/**
* #ORM\OneToMany(targetEntity="Service", mappedBy="typeOfService")
*/
private $service;
...
/**
* Constructor
*/
public function __construct()
{
$this->service = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* Add service
*
* #param \AppBundle\Entity\Service $service
* #return TypeOfService
*/
public function addService(\AppBundle\Entity\Service $service)
{
$this->service[] = $service;
return $this;
}
/**
* Remove service
*
* #param \AppBundle\Entity\Service $service
*/
public function removeService(\AppBundle\Entity\Service $service)
{
$this->service->removeElement($service);
}
/**
* Get service
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getService()
{
return $this->service;
}
}
Can anyone point me in the right direction ?
For anyone looking, I've cracked it.
This was what I was looking for:
http://symfony.com/doc/current/cookbook/form/form_collections.html
This allows for dynamic field additions, using JS.
Be careful to cascade your association. In my case:
class Facturation
{
....
/**
* #ORM\OneToMany(targetEntity="Service", mappedBy="facturation", cascade={"persist", "remove"})
*/
private $services;

Symony find in array Type

From a form of symfony I stock several values in a doctrine Array.
Then I want to do a findBy in my controller to find entites with an Id.
My entity:
<?php
/**
* Questionnaire
*
*/
class Questionnaire
{
/**
* #var integer
*
* #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 text
*
* #ORM\Column(name="description", type="text")
*/
private $description;
/**
* add unit list
* #Exclude
* #ORM\Column(name="unitids", type="array")
*/
private $unitsId = array();
public function __construct()
{
$this->unitsId = array();
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set name
*
* #param string $name
* #return Questionnaire
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* #return string
*/
public function getName()
{
return $this->name;
}
/**
* Set description
*
* #param string $description
* #return Questionnaire
*/
public function setDescription($description)
{
$this->description = $description;
return $this;
}
/**
* Get description
*
* #return string
*/
public function getDescription()
{
return $this->description;
}
/**
* Set unitsId
*
* #param array $unitsId
* #return Questionnaire
*/
public function setUnitsId($unitsId)
{
$this->unitsId = $unitsId;
return $this;
}
/**
* Get unitsId
*
* #return array
*/
public function getUnitsId()
{
return $this->unitsId;
}
}
What I want to do in my controller is to find all questionnaires which have the X unitId in UnitsId.
I tried :
$entities = $em->getRepository('Questionnaire')->findBy(array('unitsId'=>$unitId ));
But it does not work.
Is theire a way to do this ?
Thank you in advance
No, You can't do this with a Query, first You have to recover the Questionnaire object, then you have to iterate for the array because Doctrine Saves in database the array serialized and it is a lot of garbage, so You can't query directly.
find the questionarie.
Doctrine unserialize the array automatically
Iterate in the array and find the correct id.
return the result.
I Hope it Helps
I think you have to use QueryBuilder to fetch objects from joined query.

ZF2 - Database transactions with updating multiple tables

I want to use ZF2 db transaction to update multiple tables.
Normally I do transaction by something like this for a single table:
$connection = null;
try {
$connection = $this->tableGateway->getAdapter()->getDriver()->getConnection();
$connection->beginTransaction();
$this->tableGateway->insert($data);
$connection->commit();
}
catch (Exception $e) {
if ($connection instanceof \Zend\Db\Adapter\Driver\ConnectionInterface) {
$connection->rollback();
}
}
Now I want to update two tables inside one transaction. In ZF1 I did this by creating a instance of table2 class and calling its appropriate method inside same transaction. But since I don't know the method to call another model class inside a model, I cannot do as ZF1. I need this for a simple task like adding new rows to a tbl_invoice and updating tbl_runno table's running number for invoices when entering a new bill(invoice).
In your controller you can do:
$db = $this->getServiceLocator()->get('Zend\Db\Adapter\Adapter');
$con = $db->getDriver()->getConnection();
$con->beginTransaction();
try {
//get tables and do sth
$con->commit();
} catch (Exception $e) {
$con->rollback();
}
Use DataMapper design pattern. Pattern TableGateway serves to project data to a single table.
http://akrabat.com/development/objects-in-the-model-layer
http://akrabat.com/php/objects-in-the-model-layer-part-2
http://www.slideshare.net/aaronsaray/midwest-php-2013
https://leanpub.com/zendframework2-en
You can use something like this:
namespace ScContent\Mapper;
use Zend\Db\Sql\Sql;
use Zend\Db\Sql\Select;
use Zend\Db\Sql\SqlInterface;
use Zend\Db\Sql\PreparableSqlInterface;
use Zend\Db\Adapter\AdapterInterface;
use Zend\Db\Adapter\Driver\ResultInterface;
use Zend\Stdlib\Hydrator\ClassMethods;
use Zend\StdLib\Hydrator\HydratorInterface;
abstract class AbstractDbMapper
{
/**
* #var string
*/
const JoinInner = Select::JOIN_INNER;
/**
* #var string
*/
const JoinLeft = Select::JOIN_LEFT;
/**
* #var string
*/
const JoinRight = Select::JOIN_RIGHT;
/**
* #var Zend\Db\Adapter\AdapterInterface
*/
protected $_adapter;
/**
* #var Zend\Db\Sql\SqlInterface
*/
protected $_sql;
/**
* #var Zend\Stdlib\HydratorInterface
*/
protected $_hydrator;
/**
* #var array
*/
protected $_tables = array();
/**
* #param Zend\Db\Adapter\AdapterInterface $adapter
*/
public function setAdapter(AdapterInterface $adapter)
{
$this->_adapter = $adapter;
}
/**
* #return Zend\Db\Adapter\AdapterInterface
*/
public function getAdapter()
{
if(!$this->_adapter instanceof AdapterInterface) {
throw new Exception('Adapter is not installed.');
}
return $this->_adapter;
}
/**
* #param Zend\Db\Sql\SqlInterface $sql
*/
public function setSql(SqlInterface $sql)
{
$this->_sql = $sql;
}
/**
* #return Zend\Db\Sql\SqlInterface
*/
public function getSql()
{
if(!$this->_sql instanceof SqlInterface) {
$this->_sql = new Sql($this->getAdapter());
}
return $this->_sql;
}
/**
* #param Zend\Stdlib\HydratorInterface $hydrator
*/
public function setHydrator(HydratorInterface $hydrator)
{
$this->_hydrator = $hydrator;
}
/**
* #return Zend\Stdlib\HydratorInterface
*/
public function getHydrator()
{
if(!$this->_hydrator instanceof HydratorInterface) {
$this->_hydrator = new ClassMethods();
}
return $this->_hydrator;
}
/**
* #param string $alias
* #param string $name
*/
public function setTable($alias, $name)
{
$this->_tables[$alias] = $name;
}
/**
* #param string $alias
* #throws Exception
* #return string
*/
public function getTable($alias)
{
if(!array_key_exists($alias, $this->_tables)) {
throw new Exception(sprintf("Unknown table alias '%s'.", $alias));
}
return $this->_tables[$alias];
}
/**
* #return int|null|false
*/
protected function lastInsertId()
{
return $this->adapter->getDriver()->getConnection()->getLastGeneratedValue();
}
/**
* #param void
* #return void
*/
protected function beginTransaction()
{
$this->getAdapter()->getDriver()->getConnection()->beginTransaction();
}
/**
* #param void
* #return void
*/
protected function commit()
{
$this->getAdapter()->getDriver()->getConnection()->commit();
}
/**
* #return bool
*/
protected function inTransaction()
{
return $this->getAdapter()->getDriver()
->getConnection()->getResource()->inTransaction();
}
/**
* #param void
* #return void
*/
protected function rollBack()
{
$this->getAdapter()->getDriver()->getConnection()->rollBack();
}
/**
* #param Zend\Db\Sql\PreparableSqlInterface $sqlObject
* #return Zend\Db\Adapter\ResultInterface
*/
protected function execute(PreparableSqlInterface $sqlObject)
{
return $this->getSql()->prepareStatementForSqlObject($sqlObject)->execute();
}
/**
* #param Zend\Db\Adapter\ResultInterface $source
* #return array
*/
protected function toArray(ResultInterface $source)
{
$result = array();
foreach($source as $item) {
$result[] = $item;
}
return $result;
}
/**
*
*/
protected function toString(SqlInterface $sqlObject)
{
return $this->getSql()->getSqlStringForSqlObject($sqlObject);
}
}
Example of use:
<?php
namespace ScContent\Mapper;
use Zend\Db\Adapter\AdapterInterface;
class ContentMapper extends AbstractDbMapper
{
/**
* #var string
*/
const ContentTableAlias = 'contentalias';
/**
* #var string
*/
const UsersTableAlias = 'usersalias';
/**
* #param AdapterInterface $adapter
*/
public function __construct(AdapterInterface $adapter) {
$this->setAdapter($adapter);
}
/**
* #var array
*/
protected $_tables = array(
self::ContentTableAlias => 'sc_content',
self::UsersTableAlias => 'sc_users'
);
/**
* #param integer $id
* #return null | array
*/
public function findById($id)
{
$select = $this->getSql()->select()
->from(array('content' => $this->getTable(self::ContentTableAlias)))
->join(
array('users' => $this->getTable(self::UsersTableAlias)),
'content.author = users.user_id',
array('username'),
self::JoinInner
)
->where(array('`content`.`id` = ?' => $id));
return $this->execute($select)->current();
}
}

symfony2 file lost upon form error

I am using a standard implementation of file upload in connection with doctrine, as per the example on the symfony2 website tutorials.
When my upload form encounters an error in validation, and sends the user back to the form with error messages, it looses the file chosen for upload, although if I var_dump my $entity->file I can see that it has the file...
//if form is valid, do some stuff... if not:
else {
//var_dump($entity->file); //This works, I get my file
//die;
//Get and check the folder chosen as parent
$entity->setFolder( $this->checkFolderId($request->request->get('folder')) ); //will cause die() if folder doesn't belong to this company
$folders = $this->getFolders();
return $this->render('BizTVMediaManagementBundle:Image:new.html.twig', array(
'entity' => $entity,
'form' => $form->createView(),
'folders' => $folders,
'fileExists' => $fileExists,
));
}
After this is put to the twig view, there is nothing in the file field.
Here is my entity...
<?php
namespace BizTV\MediaManagementBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
/**
* BizTV\MediaManagementBundle\Entity\Image
*
* #ORM\Table(name="image")
* #ORM\Entity
* #ORM\HasLifecycleCallbacks
*/
class Image
{
/**
* #var integer $id
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string $name
*
* #ORM\Column(name="name", type="string", length=255)
* #Assert\NotBlank
*/
private $name;
/**
* #var integer $width
*
* #ORM\Column(name="width", type="integer")
*/
private $width;
/**
* #var integer $height
*
* #ORM\Column(name="height", type="integer")
*/
private $height;
/**
* #ORM\Column(type="string", length=255, nullable=true)
*/
private $path;
/**
* #var object BizTV\BackendBundle\Entity\company
*
* #ORM\ManyToOne(targetEntity="BizTV\BackendBundle\Entity\company")
* #ORM\JoinColumn(name="company", referencedColumnName="id", nullable=false)
*/
protected $company;
/**
* #var object BizTV\MediaManagementBundle\Entity\Folder
*
* #ORM\ManyToOne(targetEntity="BizTV\MediaManagementBundle\Entity\Folder")
* #ORM\JoinColumn(name="folder", referencedColumnName="id", nullable=true)
*/
protected $folder;
/**
* #Assert\File(maxSize="6000000")
*/
public $file;
/**
* #ORM\PrePersist()
* #ORM\PreUpdate()
*/
public function preUpload()
{
if (null !== $this->file) {
// do whatever you want to generate a unique name
$this->path = sha1(uniqid(mt_rand(), true)).'.'.$this->file->guessExtension();
}
}
/**
* #ORM\PostPersist()
* #ORM\PostUpdate()
*/
public function upload()
{
if (null === $this->file) {
return;
}
// if there is an error when moving the file, an exception will
// be automatically thrown by move(). This will properly prevent
// the entity from being persisted to the database on error
$this->file->move($this->getUploadRootDir(), $this->path);
unset($this->file);
}
/**
* #ORM\PostRemove()
*/
public function removeUpload()
{
if ($file = $this->getAbsolutePath()) {
unlink($file);
}
}
public function getAbsolutePath()
{
return null === $this->path ? null : $this->getUploadRootDir().'/'.$this->path;
}
public function getWebPath()
{
return null === $this->path ? null : $this->getUploadDir().'/'.$this->path;
}
protected function getUploadRootDir()
{
// the absolute directory path where uploaded documents should be saved
return __DIR__.'/../../../../web/'.$this->getUploadDir();
}
protected function getUploadDir()
{
// get rid of the __DIR__ so it doesn't screw when displaying uploaded doc/image in the view.
return 'uploads/images';
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set name
*
* #param string $name
*/
public function setName($name)
{
$this->name = $name;
}
/**
* Get name
*
* #return string
*/
public function getName()
{
return $this->name;
}
/**
* Set width
*
* #param integer $width
*/
public function setWidth($width)
{
$this->width = $width;
}
/**
* Get width
*
* #return integer
*/
public function getWidth()
{
return $this->width;
}
/**
* Set height
*
* #param integer $height
*/
public function setHeight($height)
{
$this->height = $height;
}
/**
* Get height
*
* #return integer
*/
public function getHeight()
{
return $this->height;
}
/**
* Set path
*
* #param string $path
*/
public function setPath($path)
{
$this->path = $path;
}
/**
* Get path
*
* #return string
*/
public function getPath()
{
return $this->path;
}
/**
* Set company
*
* #param BizTV\BackendBundle\Entity\company $company
*/
public function setCompany(\BizTV\BackendBundle\Entity\company $company)
{
$this->company = $company;
}
/**
* Get company
*
* #return BizTV\BackendBundle\Entity\company
*/
public function getCompany()
{
return $this->company;
}
/**
* Set folder
*
* #param BizTV\MediaManagementBundle\Entity\Folder $folder
*/
public function setFolder(\BizTV\MediaManagementBundle\Entity\Folder $folder = NULL)
{
$this->folder = $folder;
}
/**
* Get folder
*
* #return BizTV\MediaManagementBundle\Entity\Folder
*/
public function getFolder()
{
return $this->folder;
}
}
And the form:
<?php
namespace BizTV\MediaManagementBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilder;
class ImageType extends AbstractType
{
function __construct($createAction=0) {
$this->createAction = $createAction;
}
public function buildForm(FormBuilder $builder, array $options)
{
$createAction = $this->createAction;
if ($createAction) {
$builder
->add('file')
;
}
$builder
->add('name', 'text', array('label' => 'Namn'))
;
}
public function getName()
{
return 'biztv_mediamanagementbundle_imagetype';
}
}
You can't, for security purposes, set a file for the upload field. See here for more info. How to set the value of a HTML file field?
I suggest you are trying to access the file property of your entity in twig. Please take a quick look at your upload function.
/**
* #ORM\PostPersist()
* #ORM\PostUpdate()
*/
public function upload()
{
if (null === $this->file) {
return;
}
// if there is an error when moving the file, an exception will
// be automatically thrown by move(). This will properly prevent
// the entity from being persisted to the database on error
$this->file->move($this->getUploadRootDir(), $this->path);
unset($this->file);
}
As you can see the file property is being unset after the upload and persist operation has completed.
Now to have twig show your actual image you have to use the webPath property as this is the generated url to your newly uploaded image.
File uploading can be handled a bit easier with the Dustin10/VichUploaderBundle which also supports file system abstraction with KnpLabs/Gaufrette.
Hope this helps :)

Resources