Custom code format for specified code in PhpStorm - phpstorm

The PHP code for Sonata Admin using "with" is formatted by the auto formatter like this:
$formMapper->with('User')
->add('firstName')
->add('lastName')
->end()
->with('Additional Information')
->add('gender')
->end()
To get a more human readable code style I currently disable and enable the formatter and format the code like this:
// #formatter:off
$formMapper
->with('User')
->add('firstName')
->add('lastName')
->end()
->with('Additional Information')
->add('gender')
->end()
;
// #formatter:on
Is there a way to define a code style for a specific code phrase? E.g with regex to format the code automatically to the second style?

I just found a solution especially for the case in sonata admin by extending the php code to make it "autoformattable". Here is what I have done:
ObjectTypeCaster.php (from https://stackoverflow.com/a/53081037/301277):
class ObjectTypeCaster
{
/**
* This method is able to recast an object by copying all properties
*/
public static function castAs($sourceObject, $newClass)
{
$castedObject = new $newClass();
$reflectedSourceObject = new \ReflectionClass($sourceObject);
$reflectedSourceObjectProperties = $reflectedSourceObject->getProperties();
foreach ($reflectedSourceObjectProperties as $reflectedSourceObjectProperty) {
$propertyName = $reflectedSourceObjectProperty->getName();
$reflectedSourceObjectProperty->setAccessible(true);
$castedObject->$propertyName = $reflectedSourceObjectProperty->getValue($sourceObject);
}
return $castedObject;
}
}
Extend the FormMapper and ShowMapper like this:
IndentedFormMapper.php:
<?php
namespace App\Admin\Form;
use App\Helper\ObjectTypeCaster;
use Sonata\AdminBundle\Admin\AdminInterface;
use Sonata\AdminBundle\Builder\BuilderInterface;
use Sonata\AdminBundle\Builder\FormContractorInterface;
use Sonata\AdminBundle\Form\FormMapper;
use Symfony\Component\Form\FormBuilderInterface;
class IndentedFormMapper extends FormMapper
{
/**
* Makes protected property from BaseMapper public
*
* #var AdminInterface
*/
public $admin;
/**
* Makes protected property from BaseMapper public
*
* #var BuilderInterface
*/
public $builder;
/**
* Makes protected property from FormMapper public
*
* #var FormBuilderInterface
*/
public $formBuilder;
/**
* Makes protected property from BaseGroupedMapper public
*
* #var string|null
*/
public $currentGroup;
/**
* Makes protected property from BaseGroupedMapper public
*
* #var string|null
*/
public $currentTab;
/**
* Makes protected property from BaseGroupedMapper public
*
* #var bool|null
*/
public $apply;
/**
* We overwrite the constructor from FormMapper and BaseMapper to be able to create
* this object without any parameter. Its properties are copied by ObjectTypeCaster.
*
* IndentedFormMapper constructor.
*
* #see ObjectTypeCaster
*/
public function __construct()
{
}
/**
* This makes it possible to chain this object in a way that allows
* autoformatting in IntelliJ IDEs. Usage:
*
* $formMapper
* ->tab('General')
* ->chain(function ($formMapper) {
* $formMapper
* ->add('...')
* // Default usage here, you can also chain again
* ;
* })
* ->end()
* ;
*
* #param $callback
* #return $this
*/
public function chain($callback)
{
$callback($this);
return $this;
}
}
IndentedShowMapper.php:
<?php
namespace App\Admin\Form;
use App\Helper\ObjectTypeCaster;
use Sonata\AdminBundle\Admin\AdminInterface;
use Sonata\AdminBundle\Builder\BuilderInterface;
use Sonata\AdminBundle\Builder\FormContractorInterface;
use Sonata\AdminBundle\Form\FormMapper;
use Sonata\AdminBundle\Show\ShowMapper;
use Symfony\Component\Form\FormBuilderInterface;
class IndentedShowMapper extends ShowMapper
{
/**
* Makes protected property from ShowMapper public
*
* #var AdminInterface
*/
public $list;
/**
* Makes protected property from BaseGroupedMapper public
*
* #var string|null
*/
public $currentGroup;
/**
* Makes protected property from BaseGroupedMapper public
*
* #var string|null
*/
public $currentTab;
/**
* Makes protected property from BaseGroupedMapper public
*
* #var bool|null
*/
public $apply;
/**
* Makes protected property from BaseMapper public
*
* #var AdminInterface
*/
public $admin;
/**
* Makes protected property from BaseMapper public
*
* #var BuilderInterface
*/
public $builder;
/**
* We overwrite the constructor from ShowMapper and BaseMapper to be able to create
* this object without any parameter. Its properties are copied by ObjectTypeCaster.
*
* IndentedFormMapper constructor.
*
* #see ObjectTypeCaster
*/
public function __construct()
{
}
/**
* This makes it possible to chain this object in a way that allows
* autoformatting in IntelliJ IDEs. Usage:
*
* $showMapper
* ->tab('General')
* ->chain(function ($showMapper) {
* $showMapper
* ->add('...')
* // Default usage here, you can also chain again
* ;
* })
* ->end()
* ;
*
* #param $callback
* #return $this
*/
public function chain($callback)
{
$callback($this);
return $this;
}
}
Add a BaseAdmin class from that you inherit in all your admin classes and add the following methods:
<?php
use App\Admin\Form\IndentedFormMapper;
use App\Admin\Form\IndentedShowMapper;
use App\Entity\User;
use App\Helper\ObjectTypeCaster;
use Sonata\AdminBundle\Admin\AbstractAdmin;
use Sonata\AdminBundle\Datagrid\ListMapper;
use Sonata\AdminBundle\Form\FormMapper;
use Sonata\AdminBundle\Mapper\BaseMapper;
use Sonata\AdminBundle\Show\ShowMapper;
class BaseAdmin extends AbstractAdmin
{
/**
* #param FormMapper $formMapper
* #throws \ReflectionException
*/
protected function configureFormFields(FormMapper $formMapper)
{
$indentFormMapper = ObjectTypeCaster::castAs($formMapper, IndentedFormMapper::class);
$this->configureFormFieldsIndention($indentFormMapper);
}
/**
* #param IndentedFormMapper $formMapper
*/
protected function configureFormFieldsIndention(IndentedFormMapper $formMapper)
{
}
/**
* #param ShowMapper $showMapper
* #throws \ReflectionException
*/
protected function configureShowFields(ShowMapper $showMapper)
{
$indentShowMapper = ObjectTypeCaster::castAs($showMapper, IndentedShowMapper::class);
$this->configureShowFieldsIndention($indentShowMapper);
}
/**
* #param IndentedShowMapper $showMapper
*/
protected function configureShowFieldsIndention(IndentedShowMapper $showMapper)
{
}
}
Use it in your BaseAdmin child classes like this:
ExampleAdmin.php:
<?php
namespace App\Admin;
use App\Admin\Form\IndentedFormMapper;
use App\Admin\Form\IndentedShowMapper;
use App\Entity\Example;
use Sonata\AdminBundle\Datagrid\DatagridMapper;
use Sonata\AdminBundle\Datagrid\ListMapper;
use Sonata\AdminBundle\Form\FormMapper;
use Sonata\AdminBundle\Show\ShowMapper;
class ExampleAdmin extends BaseAdmin
{
// ...
/**
* #param IndentedFormMapper $formMapper
*/
protected function configureFormFieldsIndention(IndentedFormMapper $formMapper)
{
$formMapper
->tab('General')
->chain(function ($formMapper) {
$formMapper
->with(
'Example',
[
'class' => AdminLayout::HALF,
]
)
->chain(function ($formMapper) {
$formMapper
->add(
'name',
Types::TEXT
)
;
})
->end()
;
})
->end()
;
}
/**
* #param IndentedShowMapper $showMapper
*/
protected function configureShowFieldsIndention(IndentedShowMapper $showMapper)
{
$mapData = $this->getMapData();
$showMapper
->with('Internal')
->chain(function ($showMapper) {
$showMapper
->add('id')
->add('createdAt')
->add('updatedAt')
;
})
->end()
;
}
}

Related

doctrine:schema:update not updating y database

Some how whatever changes i make in my entites,doctrine doesn't seem to update it.I know there are already some similar questions.I have gone through them and tried :
php app/console cache:clear
php app/console doctrine:cache:clear-metadata
php app/console doctrine:schema:update --force
I have never imported the database,so there are no orm.yaml files in my src folder.
I am using mysql database with symfony and doctrine as orm.
here is my config
doctrine:
dbal:
driver: pdo_mysql
host: "%database_host%"
port: "%database_port%"
dbname: "%database_name%"
user: "%database_user%"
password: "%database_password%"
charset: UTF8
# if using pdo_sqlite as your database driver:
# 1. add the path in parameters.yml
# e.g. database_path: "%kernel.root_dir%/data/data.db3"
# 2. Uncomment database_path in parameters.yml.dist
# 3. Uncomment next line:
# path: "%database_path%"
orm:
auto_generate_proxy_classes: "%kernel.debug%"
naming_strategy: doctrine.orm.naming_strategy.underscore
auto_mapping: true
doctrine:schema:validate gives me this:
[Mapping] FAIL - The entity-class 'Madhuri\TermsBundle\Entity\RelatedTerm' mapping is invalid:
* The association Madhuri\TermsBundle\Entity\RelatedTerm#term1 refers to the inverse side field Madhuri\TermsBundle\Entity\Term#relatedTerm which does not exist.
My entities are
Term.php
namespace Madhuri\TermsBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
/**
* Term
*
* #ORM\Table(name="terms")
* #ORM\Entity
*/
class Term
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="termName", type="string", length=255)
*/
private $termName;
/**
* #var string
*
* #ORM\Column(name="description", type="string", length=2000)
*/
private $description;
/**
* #var string
*
* #ORM\Column(name="mnemonic", type="string", length=2000)
*/
private $mnemonic;
/**
* #var ArrayCollection
*
* #ORM\OneToMany(targetEntity="RelatedTerm",
* mappedBy="term1")
*/
private $relatedTerms;
// /**
// * #var ArrayCollection
// *
// * #ORM\OneToMany(targetEntity="TermExamples",
// * mappedBy="term")
// */
// private $termExamples;
public function __construct()
{
$this->relatedTerms = new ArrayCollection();
$this->$termExamples = new ArrayCollection();
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Get Related Terms
*/
public function getRelatedTerms()
{
return $this->relatedTerms ;
}
/**
* Add related term
*/
public function addRelatedTerm($relatedTerm)
{
$this->relatedTerms[] = $relatedTerm;
}
/**
* Clear related Terms
*/
public function clearRelatedTerms()
{
$this->relatedTerms->clear();
}
/**
* Remove a related Term
*/
public function removeRelatedTerm($relatedTerm)
{
$this->relatedTerms->removeElement($relatedTerm);
}
/**
* Get Term Examples
*/
// public function getTermExamples()
// {
// return $this->termExamples ;
// }
//
// /**
// * Add term example
// */
// public function addTermExample($termExample)
// {
// $this->termExamples[] = $termExample;
// }
//
// /**
// * Clear term examples
// */
// public function clearTermExamples()
// {
// $this->termExamples->clear() ;
// }
//
// /**
// * Remove a Term Example
// */
// public function removeTermExample($termExample)
// {
// $this->termExamples->removeElement($termExample);
// }
/**
* Set termName
*
* #param string $termName
* #return Term
*/
public function setTermName($termName)
{
$this->termName = $termName;
return $this;
}
/**
* Get termName
*
* #return string
*/
public function getTermName()
{
return $this->termName;
}
/**
* Set description
*
* #param string $description
* #return Term
*/
public function setDescription($description)
{
$this->description = $description;
return $this;
}
/**
* Get description
*
* #return string
*/
public function getDescription()
{
return $this->description;
}
/**
* Set mnemonic
*
* #param string $mnemonic
* #return Term
*/
public function setMnemonic($mnemonic)
{
$this->mnemonic = $mnemonic;
return $this;
}
/**
* Get mnemonic
*
* #return string
*/
public function getMnemonic()
{
return $this->mnemonic;
}
}
RelatedTerm.php
<?php
namespace Madhuri\TermsBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* RelatedTerms
*
* #ORM\Table(name="related_terms")
* #ORM\Entity
*/
class RelatedTerm
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var Term
*
* #ORM\ManyToOne(targetEntity="Term",
* inversedBy="relatedTerm")
*/
private $term1;
/**
* #var Term
*
* #ORM\ManyToOne(targetEntity ="Term")
*/
private $term2;
/**
* #var string
*
* #ORM\Column(name="notes", type="string", length=2000, nullable=true)
*/
private $notes;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Get term1
*
* #return Term
*/
public function getTerm1()
{
if($this->term1)
{
return $this->term1;
}
else {
return null;
}
}
/**
* Set term1
*
* #param Term $term1
*
* #return Term
*/
public function setTerm1(Term $term1)
{
$this->term1 = $term1;
return $this;
}
/**
* Get term2
*
* #return Term
*/
public function getTerm2()
{
return $this->term2;
}
/**
* Set term2
*
* #param Term $term2
*
* #return Term
*/
public function setTerm2( Term $term2)
{
$this->term2 = $term2;
return $this;
}
/**
* Get notes
*
* #return string
*/
public function getNotes()
{
return $this->notes;
}
/**
* Set notes
*
* #param string $notes
*
* #return Term
*/
public function setNotes($notes)
{
$this->notes = $notes;
return $this;
}
}
?>
If you are using doctrine without framework (like i do), delete the calling to doctrine as ORM (maybe not needed)
use Doctrine\ORM\Mapping as ORM;
then replace all the #ORM\ for just #.
This was stopping doctrine from recognizing the class and its changes.
Hope it helps

Doctrine 2 and vertical partitioning

I'm currently working on a project for which i have to deal with a lot of users fields (+/- 80). My first approach was (and still is) to vertically partition the user table in 4 tables : main informations, administrative informations, banking informations, statistics informations. The ids of the 3 extra tables rows refer to the auto incremented id of the main table.
My questions are :
Is it relevant to do so ?
It seems like, with the way i did the
association, Doctrine isn't able to flush one object into database
in one shot :
Entity of type MyVendor\User\UserBundle\Entity\UsersInfosBank is missing an
assigned ID for field 'id_user'. The identifier generation strategy
for this entity requires the ID field to be populated before
EntityManager#persist() is called. If you want automatically generated
identifiers instead you need to adjust the metadata mapping
accordingly.
The project will be pushed into production in 3 weeks, so we're still able to go back to a more traditionnal way to store these datas into one huge table…
****************UPDATE*****************
WHOLE CODE LOGIC BELOW*****************
I just removed most of the properties and methods which are not concerned by my problem…
And yes, i'm using FOSUserBundle ;)
UsersMain
<?php
namespace LCP\User\UserBundle\Entity;
use FOS\UserBundle\Model\GroupableInterface;
use FOS\UserBundle\Model\User as BaseUser;
use Doctrine\ORM\Mapping as ORM;
/**
* UsersMain
*
* #ORM\Table(name="lcp_users_main")
* #ORM\Entity
*/
class UsersMain extends BaseUser
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
*
* #ORM\OneToOne(targetEntity="LCP\User\UserBundle\Entity\UsersInfosBank", mappedBy="id_user", cascade={"persist"})
*/
private $infosBank;
/**
*
* #ORM\OneToOne(targetEntity="LCP\User\UserBundle\Entity\UsersApodis", mappedBy="id_user", cascade={"persist"})
*/
private $apodis;
/**
*
* #ORM\OneToOne(targetEntity="LCP\User\UserBundle\Entity\UsersInfosAdmin", mappedBy="id_user", cascade={"persist"})
*/
private $infosAdmin;
/**
*
* #ORM\OneToOne(targetEntity="LCP\User\UserBundle\Entity\UsersInfosStats", mappedBy="id_user", cascade={"persist"})
*/
private $infosStats;
/**
* Constructor
*/
public function __construct()
{
$this->groups = new \Doctrine\Common\Collections\ArrayCollection();
$this->creationDate = new \Datetime();
}
/**
* Set apodis
*
* #param \LCP\User\UserBundle\Entity\UsersApodis $apodis
* #return UsersMain
*/
public function setApodis(\LCP\User\UserBundle\Entity\UsersApodis $apodis = null)
{
if(is_null($this->apodis) && is_null($apodis)){
$this->apodis = new \LCP\User\UserBundle\Entity\UsersApodis();
} else {
$this->apodis = $infosBank;
}
$this->apodis->setIdUser($this);
return $this;
}
/**
* Get apodis
*
* #return \LCP\User\UserBundle\Entity\UsersApodis
*/
public function getApodis()
{
if(is_null($this->infosAdmin)){
$this->infosAdmin = new \LCP\User\UserBundle\Entity\UsersApodis();
}
return $this->apodis;
}
/**
* Set infosAdmin
*
* #param \LCP\User\UserBundle\Entity\UsersInfosAdmin $infosAdmin
* #return UsersMain
*/
public function setInfosAdmin(\LCP\User\UserBundle\Entity\UsersInfosAdmin $infosAdmin = null)
{
if(is_null($this->infosAdmin) && is_null($infosAdmin)){
$this->infosAdmin = new \LCP\User\UserBundle\Entity\UsersInfosAdmin();
} else {
$this->infosAdmin = $infosAdmin;
}
$this->infosAdmin->setIdUser($this);
return $this;
}
/**
* Get infosAdmin
*
* #return \LCP\User\UserBundle\Entity\UsersInfosAdmin
*/
public function getInfosAdmin()
{
if(is_null($this->infosAdmin)){
$this->infosAdmin = new \LCP\User\UserBundle\Entity\UsersInfosAdmin();
}
return $this->infosAdmin;
}
/**
* Set infosStats
*
* #param \LCP\User\UserBundle\Entity\UsersInfosStats $infosStats
* #return UsersMain
*/
public function setInfosStats(\LCP\User\UserBundle\Entity\UsersInfosStats $infosStats = null)
{
if(is_null($this->infosStats) && is_null($infosStats)){
$this->infosStats = new \LCP\User\UserBundle\Entity\UsersInfosStats();
} else {
$this->infosStats = $infosAdmin;
}
$this->infosStats->setIdUser($this);
return $this;
}
/**
* Get infosStats
*
* #return \LCP\User\UserBundle\Entity\UsersInfosStats
*/
public function getInfosStats()
{
if(is_null($this->infosStats)){
$this->infosStats = new \LCP\User\UserBundle\Entity\UsersInfosStats();
}
return $this->infosStats;
}
}
UsersInfosAdmin
<?php
namespace LCP\User\UserBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* UsersInfosAdmin
*
* #ORM\Table(name="lcp_users_infos_admin", indexes={#ORM\Index(name="pharmacyCip_idx", columns={"pharmacy_cip"})})
* #ORM\Entity
*/
class UsersInfosAdmin
{
/**
* #var integer
* #ORM\Id
* #ORM\OneToOne(targetEntity="LCP\User\UserBundle\Entity\UsersMain", cascade={"persist"}, inversedBy="infosAdmin")
*/
private $id_user;
/**
* Set id_user
*
* #param \LCP\User\UserBundle\Entity\UsersMain $idUser
* #return UsersInfosAdmin
*/
public function setIdUser(\LCP\User\UserBundle\Entity\UsersMain $idUser)
{
$this->id_user = $idUser;
return $this;
}
/**
* Get id_user
*
* #return \LCP\User\UserBundle\Entity\UsersMain
*/
public function getIdUser()
{
return $this->id_user;
}
}
UsersInfosStats
<?php
namespace LCP\User\UserBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* UsersInfosStats
*
* #ORM\Table(name="lcp_users_infos_stats")
* #ORM\Entity
*/
class UsersInfosStats
{
/**
* #var integer
* #ORM\Id
* #ORM\OneToOne(targetEntity="LCP\User\UserBundle\Entity\UsersMain", cascade={"persist"}, inversedBy="infosStats")
*/
private $id_user;
/**
* Set id_user
*
* #param \LCP\User\UserBundle\Entity\UsersMain $idUser
* #return UsersInfosStats
*/
public function setIdUser(\LCP\User\UserBundle\Entity\UsersMain $idUser)
{
$this->id_user = $idUser;
return $this;
}
/**
* Get id_user
*
* #return \LCP\User\UserBundle\Entity\UsersMain
*/
public function getIdUser()
{
return $this->id_user;
}
}
Here is how i create a user (it is through a secured admin area form) :
/**
* This action get the field from the form
*/
public function userSaveAction(Request $request)
{
$userManager = $this->get('fos_user.user_manager');
$this->request = $request;
$userValues = $this->getRequest()->request->all();
$this->em = $this->getDoctrine()->getManager();
$user = $this->processUser($userValues);
$userManager->updateUser($user, false);
return $this->redirect($this->generateUrl('lcp_admin_user_edit', ['id'=>$user->getId()]));
}
/**
* This method process user fields and uses setters (or getters for joined entities) to set datas of user
*/
private function processUser($userValues)
{
if($userValues['userId']=="") {
$user = $this->get('fos_user.user_manager')->createUser();
} else {
$user = $this->em->getRepository('LCPUserBundle:UsersMain')
->findOneBy(['id' => $userId]);
}
//construction of related entities
$user->setInfosAdmin();
$user->setInfosBank();
$user->setInfosStats();
$user->setApodis();
unset($userValues['userId']);
//this method inspect submitted field to check if they are mandatory or if current user is allowed to modify them
$this->fields = $this->getInfosFields();
foreach($userValues as $input=>$value){
list($entity,$input)=explode('-',$input);
if($input=='plainPassword' && $value==''){
continue;
}
if($entity=='Main'){
$setter = 'set'.ucfirst($input);
$user->$setter($value);
} else {
$setter = 'set'.ucfirst($input);
$join = 'get'.$entity;
$user->$join()->$setter($value);
}
}
return $user;
}
According to the comments your UsersMain property need to be like this:
/**
* Join administrative informations
* #ORM\OneToOne(targetEntity="MyVendor\User\UserBundle\Entity\UsersInfosAdmin", mappedBy="userMain", cascade={"persist"}, orphanRemoval=true)
*/
private $infosAdmin;
/**
* Setter InfosAdmin
*/
public function setInfosAdmin(UsersInfosAdmin $infosAdmin)
{
$this->infosAdmin = $infosAdmin;
$this->infosAdmin->setUserMain($this); <--- add this to set userMain on associated object
return $this;
}
then your UsersInfosAdmin properties need to be like this:
/**
* #var integer
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\OneToOne(targetEntity="MyVendor\User\UserBundle\Entity\UsersMain", inversedBy="userMain")
*/
private $userMain;

dynamic creating and mapping new field in doctrine/symfony/mysql

Every quartal (each 3-month) i need into table "report" add new "column" - for example "Y2014Q1" where Y=year and Q=quartal (1,2,3,4). After creating I need to make mapping of this new column in to object.
Part of my code is:
namespace backend\backendBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* FactSheetData
*
* #ORM\Table(name="report")
* #ORM\Entity
*/
class ReportData
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="Y2016Q3", type="string")
*/
private $Y2016Q3;
/**
* #param string $Y2016Q3
*/
public function setY2016Q3($Y2016Q3)
{
$this->Y2016Q3 = $Y2016Q3;
}
/**
* #return string
*/
public function getY2016Q4()
{
return $this->Y2016Q4;
}
....
I need to do something like this when new period comes:
class ReportData {
public function __construct() {
// if new perriod alter table
if (test_new_perriod) {
$new_period='Y2016Q4';
$sql="ALTER TABLE `report` ADD COLUMN `".$new_period."` VARCHAR(50) NULL DEFAULT NULL;";
$stmt = $this->getEntityManager()->getConnection()->prepare($sql);
$stmt->execute();
//and now - this is problem how to do - dynamic maping
/**
* #var string
*
* #ORM\Column(name="$new_period", type="string")
*/
private $new_period;
/**
* #param string $new_period
*/
public function set$new_period($new_period)
{
$this->$new_period =$new_period;
}
/**
* #return string
*/
public function get$new_period()
{
return $this->$new_period;
}
}
}
Hope I describe clear... Thanx for any advice.

Symfony2: embedding form with many-to-many entities throws exception

Issue
I've been trying to follow the tutorial to embed a form in another one. What I'm trying to do here is add a task, and add multiple categories to it. I'm using the example at http://symfony.com/doc/current/book/forms.html#embedding-a-single-object, but I added some ORM annotations to make the relation many-to-many. As such, here is my code for the Task & Category entities:
Code
Task entity
<?php
namespace Acme\TaskBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
/**
* Task
*
* #ORM\Table()
* #ORM\Entity
*/
class Task
{
/**
* #ORM\ManyToMany(targetEntity="Category", inversedBy="tasks")
* #ORM\JoinTable(name="tasks_categories")
*
* #Assert\Type(type="Acme\TaskBundle\Entity\Category")
*/
protected $categories;
// ...
/**
* #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;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set name
*
* #param string $name
* #return Task
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* #return string
*/
public function getName()
{
return $this->name;
}
/**
* Constructor
*/
public function __construct()
{
$this->categories = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* Add categories
*
* #param \Acme\TaskBundle\Entity\Category $categories
* #return Task
*/
public function addCategorie(\Acme\TaskBundle\Entity\Category $categories)
{
$this->categories[] = $categories;
return $this;
}
/**
* Remove categories
*
* #param \Acme\TaskBundle\Entity\Category $categories
*/
public function removeCategorie(\Acme\TaskBundle\Entity\Category $categories)
{
$this->categories->removeElement($categories);
}
/**
* Get categories
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getCategories()
{
return $this->categories;
}
}
Category entity
<?php
namespace Acme\TaskBundle\Entity;
use Symfony\Component\Validator\Constraints as Assert;
use Doctrine\ORM\Mapping as ORM;
/**
* Category
*
* #ORM\Table()
* #ORM\Entity
*/
class Category
{
/**
* #ORM\ManyToMany(targetEntity="Task", mappedBy="categories")
*/
private $tasks;
/**
* #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;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set name
*
* #param string $name
* #return Category
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* #return string
*/
public function getName()
{
return $this->name;
}
/**
* Constructor
*/
public function __construct()
{
$this->tasks = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* Add tasks
*
* #param \Acme\TaskBundle\Entity\Task $tasks
* #return Category
*/
public function addTask(\Acme\TaskBundle\Entity\Task $tasks)
{
$this->tasks[] = $tasks;
return $this;
}
/**
* Remove tasks
*
* #param \Acme\TaskBundle\Entity\Task $tasks
*/
public function removeTask(\Acme\TaskBundle\Entity\Task $tasks)
{
$this->tasks->removeElement($tasks);
}
/**
* Get tasks
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getTasks()
{
return $this->tasks;
}
}
Both forms have been auto-generated by using the doctrine:generate:form command. I changed the TaskType form to include the categories:
TaskType form
<?php
namespace Acme\TaskBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class TaskType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name')
->add('categories', new CategoryType())
;
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Acme\TaskBundle\Entity\Task',
'cascade_validation' => true,
));
}
public function getName()
{
return 'task';
}
}
Now when I go to the create page for tasks, I get this error:
The form's view data is expected to be an instance of class
Acme\TaskBundle\Entity\Category, but is an instance of class
Doctrine\Common\Collections\ArrayCollection. You can avoid this error
by setting the "data_class" option to null or by adding a view
transformer that transforms an instance of class
Doctrine\Common\Collections\ArrayCollection to an instance of
Acme\TaskBundle\Entity\Category.
I honestly have no idea how to fix it since this seemed a pretty straight-forward thing but apparently it isn't. Could someone help me out here please?
in your Task Entity remove the validation for categories.
Symfony tries to validate a ArrayCollection as one Category!(hence the error)
* #Assert\Type(type="Acme\TaskBundle\Entity\Category")
*/
$categories;
It isn't necessary since it is a collection. (validation will be based on what type of objects are in the collection)
If you created a CategoryType form then this form should return Acme\TaskBundle\Entity\Category for it's data class.
class CategoryType {
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Acme\TaskBundle\Entity\Category',
.....
));
}
}
Also, in your TaskType
$builder
->add('name')
->add('categories', new CategoryType()) // new CategoryType()
// is not really needed here,
// symfony will automatically detect
// it's relation and create a new
// CategoryType if necessary.

JMSSerializerBundleThe Response content must be a string or object implementing __toString()"

I've got a problem with JMSSerializerBundle.
I have my entity AGVote there :
<?php
namespace K\AGBundle\Entity;
use JMS\SerializerBundle\Annotation\Type;
use JMS\SerializerBundle\Annotation\Accessor;
use JMS\SerializerBundle\Annotation\AccessType;
use JMS\SerializerBundle\Annotation\Exclude;
use JMS\SerializerBundle\Annotation\ExclusionPolicy;
use Doctrine\ORM\Mapping as ORM;
/**
* K\AGBundle\Entity\AGVote
* #ORM\Entity
* #ORM\HasLifecycleCallbacks
*
*/
/*
*
/** #AccessType("public_method") */
class AGVote
{
/**
* #Type("integer")
* #Accessor(getter="getId")
*/
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
public $id;
/**
* #ORM\Column(type="text")
* #Accessor(getter="getQuestion")
* #Type("text")
*/
public $question;
/**
* #ORM\Column(type="smallint")
* #Type("integer")
* #Accessor(getter="getActif")
*/
public $actif;
/**
* #ORM\ManyToOne(targetEntity="\K\KBundle\Entity\Users", cascade={"all"})
* #Exclude
*/
protected $users;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set question
* Nb : Only AG admin can set a question
* #param text $question
*/
public function setQuestion($question)
{
$this->question = $question;
}
/**
* Get question
*
* #return text
*/
public function getquestion()
{
return $this->question;
}
/**
* Set actif
*
* #param smallint $actif
*/
public function setActif($actif)
{
$this->actif = $actif;
}
/**
* Get actif
*
* #return smallint
*/
public function getActif()
{
return $this->actif;
}
/**
* Set Users
*
* #param K\KBundle\Entity\Province $Users
*/
public function setUsers(\K\KBundle\Entity\Users $users)
{
$this->users = $users;
}
/**
* Get Users
*
* #return K\KBundle\Entity\Users
*/
public function getUsers()
{
return $this->users;
}
public function __toString()
{
return $this->getquestion();
}
}
I have made a controller that juste return me an AGVote Entity in Json :
public function jsonvoteAction($id) {
$em = $this->getDoctrine()->getEntityManager();
$entity = $em->getRepository('KAGBundle:AGVote')->findOneById($id);
if ($entity->getActif() == 1) {
$serializer = $this->container->get('serializer');
$serializer->serialize($entity, 'json');
$response = new Response($serializer);
return $reponse;
}
}
I have a response in Json but it is a error saying :
[{"message":"The Response content must be a string or object implementing __toString(), \"object\" given.","class":"UnexpectedValueException","trace":
In fact I have already implement a __toString() method inside of all my entities.
Does anyone have an idea ?
Thanks you :)
When you call the serialize method on the $serializer, it returns the serialized data (a string).
The problem is that you do not use this returned value, and create the response with the $serializer itself, which makes no sense.
First, store the serialized $entity:
$serializedEntity = $serializer->serialize($entity, 'json');
Then, you can return a new response using with string:
return new Response($serializedEntity, 200, array('Content-Type' => 'application/json'));