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();
}
}
Related
I would like to use a controller for downloading files.
The request is coming via an entity url and an included custom controller.
In the invoke function the requested file will be sent to the browser.
The problem is that the swagger documentation will be shown in a browser, the output of the controller will be ignored.
Only via a postman request the file content will be shown.
A solution would be to disable swagger for this entity.
Entity:
<?php
namespace App\Entity;
use ApiPlatform\Core\Annotation\ApiProperty;
use ApiPlatform\Core\Annotation\ApiResource;
use App\Controller\GetMediaObjectAction;
/**
* #ApiResource(
* attributes={
* "route_prefix"="/api"
* },
* collectionOperations={},
* itemOperations={
* "archiveapi_get_file"={
* "path"="/file/{company_id}/{id}/{filename}",
* "defaults"={"_api_receive"=false},
* "read"=false,
* "requirements" = {
* "company_id" = "\d+",
* "id" = ".+",
* "filename" = "(.+)\.(.+)",
* },
* }
* },
* normalizationContext={"groups"={"MediaObject:read"}}
* )
*/
class MediaObject
{
/**
* #var string|null
*
* #ApiProperty(identifier=true)
*/
protected $id = null;
/**
* #var string|null
*
* #ApiProperty(identifier=true)
*/
protected $companyId = null;
/**
* #var string|null
*
* #ApiProperty(identifier=true)
*/
protected $filename = null;
/**
* #return string|null
*/
public function getId(): ?string
{
return $this->id;
}
/**
* #param string|null $id
* #return MediaObject
*/
public function setId(?string $id): MediaObject
{
$this->id = $id;
return $this;
}
/**
* #return string|null
*/
public function getCompanyId(): ?string
{
return $this->companyId;
}
/**
* #param string|null $companyId
* #return MediaObject
*/
public function setCompanyId(?string $companyId): MediaObject
{
$this->companyId = $companyId;
return $this;
}
/**
* #return string|null
*/
public function getFilename(): ?string
{
return $this->filename;
}
/**
* #param string|null $filename
* #return MediaObject
*/
public function setFilename(?string $filename): MediaObject
{
$this->filename = $filename;
return $this;
}
}
Controller:
<?php
namespace App\Controller;
use App\Entity\MediaObject;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\BinaryFileResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\Routing\Annotation\Route;
use function PHPUnit\Framework\throwException;
final class GetMediaObjectAction extends AbstractController
{
/**
* #Route(
* name="archiveapi_get_file",
* path="/file/{companyId}/{id}/{filename}",
* methods={"GET"},
* defaults={
* "_api_resource_class"=MediaObject::class,
* "_api_item_operation_name"="archiveapi_get_file",
* "_api_receive"=false,
* "_api_respond"=false
* }
* )
*/
public function __invoke(Request $request, $companyId, $id, $filename): BinaryFileResponse
{
$projectDir = $this->getParameter('kernel.project_dir');
$file = sprintf("%s/var/data/invoices_%s/%s/%s", $projectDir, $companyId, $id, $filename);
if (!file_exists($file)) {
throw new NotFoundHttpException('file not available');
}
return new BinaryFileResponse($file);
}
}
I want to create a sorted Menu in PHP, Symfony which could be very deep.
Therefor I have added 2 fields in category db (parent_id, sort).
My problem is to get a sorted array like:
array(
//MAIN CATEGORY 1
array(
'id' => 1,
'name' => 'Main',
'child'=> false
),
//MAIN CATEGORY 2
array(
'id' => 2,
'name' => 'Main2',
'child'=> false
),
//MAIN CATEGORY 3
array(
'id' => 6,
'name' => 'Main3',
'child'=> array(
array(
'id' => 4,
'name' => 'Sub of Main3',
'child'=> array(
'id' => 4,
'name' => 'Sub Sub og Main3',
'child'=> false
)
),
array(
'id' => 7,
'name' => '2. Sub og Main3',
'child'=> false
)
)
)
);
So I can use it to create the menu with KnpMenu Bundle.
I could not find another way, which is economical in performance and works with this bundle.
Can anybody help me, how to create the array out of the DB?
I tested something around and found a solution with knpMenuBundle like this:
namespace AppBundle\Menu;
use Knp\Menu\FactoryInterface;
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
use Symfony\Component\DependencyInjection\ContainerAwareTrait;
class Builder implements ContainerAwareInterface
{
use ContainerAwareTrait;
public function mainMenu(FactoryInterface $factory, array $options)
{
$em = $this->container->get('doctrine')->getManager();
$mandant = $this->container->get('session')->get('mandantId');
$nodes = $em->getRepository('AppBundle:Categories')->findSorted($mandant);
$menu = $factory->createItem('root');
$menu->addChild('Startseite', array('route' => 'homepage'));
foreach($nodes as $node)
{
$childMenu = $menu->addChild($node['name'],array('route' => $node['route']));
$this->loadChild($childMenu,$node);
}
return $menu;
}
private function loadChild($childMenu,array $node)
{
if(isset($node['child']))
{
foreach ($node['child'] as $child)
{
$childMenu = $childMenu->addChild($child['name'],array('route' => $child['route']));
$this->loadChild($childMenu,$child);
}
}
return;
}
I had a very similar issue and here is how I solved it.
So my page entity looks something like this:
<?php
namespace AppBundle\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
use Knp\Menu\NodeInterface;
/**
* Page
*
* #ORM\Table(name="PAGE")
* #ORM\Entity()
*/
class Page implements NodeInterface
{
/**
* #var int
*
* #ORM\Column(name="ID", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="TITLE", type="string", length=255)
*/
private $title;
/**
* page | link | pdf
* #var string
*
* #ORM\Column(name="CONTENT_TYPE", type="string", length=255)
*/
private $contentType;
/**
* A page can have one parent
*
* #var FacetPage
*
* #ORM\ManyToOne(targetEntity="Page", inversedBy="childrenPages")
* #ORM\JoinColumn(name="PARENT_PAGE_ID", referencedColumnName="ID")
*/
private $parentPage;
/**
* A parent can have multiple children
*
* #var arrayCollection
*
* #ORM\OneToMany(targetEntity="Page", mappedBy="parentPage")
*
*/
private $childrenPages;
/**
* #var resource
*
* #ORM\Column(name="CONTENT", type="text", length=200000)
*/
private $content;
/**
* Many pages could have many allowed roles
*
* #var arrayCollection
*
* #ORM\ManyToMany(targetEntity="Role")
* #ORM\JoinTable(name="PAGE_ALLOWED_ROLES",
* joinColumns={#ORM\JoinColumn(name="page_id", referencedColumnName="ID")},
* inverseJoinColumns={#ORM\JoinColumn(name="role_id", referencedColumnName="ID")}
* )
*/
private $allowedRoles;
/**
* #var string
*
* #ORM\Column(name="SLUG", type="string", nullable=true)
*/
private $slug;
/**
* #var string
*
* #ORM\Column(name="PERMALINK", type="string", nullable=true)
*/
private $permalink;
/**
* #var User
*
* #ORM\ManyToOne(targetEntity="User")
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="CREATED_BY", referencedColumnName="ID", nullable=false)
* })
*
*/
private $author;
/**
* #var \DateTime
*
* #ORM\Column(name="CREATED_ON", type="datetime", nullable=false)
*/
private $createdOn;
/**
* The default status of new pages is published
*
* #var string
*
* #ORM\Column(name="STATUS", type="string", nullable=false, )
*/
private $status = 'published';
/**
* Page constructor.
*/
public function __construct( ) {
//https://knpuniversity.com/screencast/collections/many-to-many-setup#doctrine-arraycollection
$this->allowedRoles = new ArrayCollection();
$this->childrenPages = new ArrayCollection();
}
/**
* #return int
*/
public function getId()
{
return $this->id;
}
/**
* #param int $id
*/
public function setId( int $id )
{
$this->id = $id;
}
/**
* #return string
*/
public function getTitle()
{
return $this->title;
}
/**
* #param string $title
*/
public function setTitle( string $title )
{
$this->title = $title;
}
/**
* #return string
*/
public function getContentType()
{
return $this->contentType;
}
/**
* #param string $contentType
*/
public function setContentType( string $contentType )
{
$this->contentType = $contentType;
}
/**
* #return Page
*/
public function getParentPage()
{
return $this->parentPage;
}
/**
* #param Page $parentPage
*/
public function setParentPage( Page $parentPage )
{
$this->parentPage = $parentPage;
}
/**
* #return string
*/
public function getContent()
{
return $this->content;
}
/**
* #param string $content
*/
public function setContent( string $content )
{
$this->content = $content;
}
/**
* #return ArrayCollection|Role[]
*/
public function getAllowedRoles()
{
return $this->allowedRoles;
}
/**
* #param arrayCollection $allowedRoles
*/
public function setAllowedRoles( $allowedRoles )
{
$this->allowedRoles = $allowedRoles;
}
/**
* #return string
*/
public function getSlug()
{
return $this->slug;
}
/**
* #param string $slug
*/
public function setSlug( string $slug )
{
$this->slug = $slug;
}
/**
* #return string
*/
public function getPermalink()
{
return $this->permalink;
}
/**
* #param string $permalink
*/
public function setPermalink( string $permalink )
{
$this->permalink = $permalink;
}
/**
* #return User
*/
public function getAuthor()
{
return $this->author;
}
/**
* #param FacetUser $author
*/
public function setAuthor( User $author )
{
$this->author = $author;
}
/**
* #return \DateTime
*/
public function getCreatedOn()
{
return $this->createdOn;
}
/**
* #param \DateTime $createdOn
*/
public function setCreatedOn( \DateTime $createdOn )
{
$this->createdOn = $createdOn;
}
/**
* #return string
*/
public function getStatus()
{
return $this->status;
}
/**
* #param string $status
*/
public function setStatus( string $status )
{
$this->status = $status;
}
/**
* #return ArrayCollection
*/
public function getChildrenPages()
{
return $this->childrenPages;
}
/**
* #param ArrayCollection $childrenPages
*/
public function setChildrenPages( $childrenPages )
{
$this->childrenPages = $childrenPages;
}
/**
* Get the name of the node
*
* Each child of a node must have a unique name
*
* #return string
*/
public function getName() {
return $this->title;
}
/**
* Get the options for the factory to create the item for this node
*
* #return array
* #throws \Exception
*/
public function getOptions() {
if($this->contentType == 'page'){
return [
'route' => 'core_page_id',
'routeParameters' => ['id'=>$this->id]
];
}
if($this->contentType == 'doc'){
return [
'uri'=>'/'.$this->getContent()
];
}
if($this->contentType == 'link'){
return [
'uri'=>$this->content
];
}
throw new \Exception('No valid options found for page type',500);
}
/**
* Get the child nodes implementing NodeInterface
*
* #return \Traversable
*/
public function getChildren() {
return $this->getChildren();
}
}
The main difference here is that it implements Knp's NodeInterface and its functions which are defined at the end of the entity, getName(), getOptions(), and getChildren().
Now on to my Builder, which basically does the same thing as your recursive function.
<?php
namespace AppBundle\Menu;
use AppBundle\Entity\Page;
use Knp\Menu\FactoryInterface;
use Knp\Menu\ItemInterface;
use Knp\Menu\MenuItem;
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
use Symfony\Component\DependencyInjection\ContainerAwareTrait;
class Builder implements ContainerAwareInterface
{
use ContainerAwareTrait;
/** #var ItemInterface */
private $menu;
/**
* #param FactoryInterface $factory
* #param array $options
*
* #return ItemInterface
*/
public function mainMenu(FactoryInterface $factory, array $options)
{
$this->menu = $factory->createItem('root');
$this->menu->addChild('Home', array('route' => 'core_homepage'));
$em = $this->container->get('doctrine')->getManager();
// get all published pages
$pages = $em->getRepository(Page::class)->findBy(['status'=>'published']);
// build pages
try {
$this->buildPageTree( $pages );
} catch ( \Exception $e ) {
error_log($e->getMessage());
}
return $this->menu;
}
/**
*
* #param array $pages
* #param Page $parent
* #param MenuItem $menuItem
*
* #throws \Exception
*/
private function buildPageTree(array $pages, $parent = null, $menuItem = null)
{
/** #var Page $page */
foreach ($pages as $page) {
// If page doesn't have a parent, and no menuItem was passed then this is a top level add.
if(empty($page->getParentPage()) && empty($menuItem) )
$parentMenu = $this->menu->addChild($page->getTitle(), $page->getOptions());
// if the current page's parent is === supplied parent, go deeper
if ($page->getParentPage() === $parent) {
// if a menuItem was given, then this page is a child so added it to the provided menu.
if(!empty($menuItem))
$parentMenu = $menuItem->addChild($page->getTitle(), $page->getOptions());
// go deeper
$this->buildPageTree($pages, $page, $parentMenu);
}
}
}
}
I hope this helps in some way!
I would like to know how to save the accent character é as é in a mysql database when it is inserted in a form in Symfony2. The explanation is as below:
This the code of the form builder I have:
<?php
namespace Ikproj\GroupeBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class MessagesType extends AbstractType
{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('contenu','textarea', array('attr' => array('rows' => '6','cols' => '40')));
}
/**
* #param OptionsResolverInterface $resolver
*/
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Ikproj\GroupeBundle\Entity\Messages'
));
}
/**
* #return string
*/
public function getName()
{
return 'ikproj_groupebundle_messages';
}
}
This is the code of the entity belonged to the form builder above:
<?php
namespace Ikproj\GroupeBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Messages
*
* #ORM\Table(name="messages")
* #ORM\Entity(repositoryClass="Ikproj\GroupeBundle\Entity\MessagesRepository")
*/
class Messages
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var integer
*
* #ORM\Column(name="actor", type="integer")
*/
private $actor;
/**
* #var integer
*
* #ORM\Column(name="subject", type="integer")
*/
private $subject;
/**
* #var string
*
* #ORM\Column(name="contenu", type="string")
*/
private $contenu;
/**
* #var string
*
* #ORM\Column(name="status", type="string", length=10)
*/
private $status;
/**
* #var string
*
* #ORM\Column(name="type", type="string", length=10)
*/
private $type;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set actor
*
* #param integer $actor
* #return Messages
*/
public function setActor($actor)
{
$this->actor = $actor;
return $this;
}
/**
* Get actor
*
* #return integer
*/
public function getActor()
{
return $this->actor;
}
/**
* Set subject
*
* #param integer $subject
* #return Messages
*/
public function setSubject($subject)
{
$this->subject = $subject;
return $this;
}
/**
* Get subject
*
* #return integer
*/
public function getSubject()
{
return $this->subject;
}
/**
* Set contenu
*
* #param string $contenu
* #return Messages
*/
public function setContenu($contenu)
{
$this->contenu = $contenu;
return $this;
}
/**
* Get contenu
*
* #return string
*/
public function getContenu()
{
return $this->contenu;
}
/**
* Set status
*
* #param string $status
* #return Messages
*/
public function setStatus($status)
{
$this->status = $status;
return $this;
}
/**
* Get status
*
* #return string
*/
public function getStatus()
{
return $this->status;
}
/**
* Set type
*
* #param string $type
* #return Messages
*/
public function setType($type)
{
$this->type = $type;
return $this;
}
/**
* Get type
*
* #return string
*/
public function getType()
{
return $this->type;
}
}
This is the code of the controller I have:
public function SendMessageAction(Request $request, $actor, $subject, $cible) {
$message = new Messages();
$form = $this->createForm(new MessagesType(), $message);
$em = $this->getDoctrine()->getManager();
$actor1 = $actor;
$subject1 = $subject;
$status1 = "unseen";
$cible1 = $cible;
if ($request->isMethod('POST')) {
$form->handleRequest($request);
if ($form->isValid()) {
$message->setActor($actor1);
$message->setSubject($subject1);
$message->setStatus($status1);
$message->setType($cible1);
$em->persist($message);
$em->flush();
return $this->redirect($this->generateUrl('task_success'));
}
}
else {
return $this->render('IkprojGroupeBundle:Messages:SendMessage.html.twig', array(
'form' => $form->createView(),
'actor' => $actor,
'subject' => $subject,
'cible' => $cible
));
}
}
And this is the code of the file config.yml belonged to the doctrine configuration:
doctrine:
dbal:
driver: "%database_driver%"
host: "%database_host%"
port: "%database_port%"
dbname: "%database_name%"
user: "%database_user%"
password: "%database_password%"
charset: UTF8
The problem is that when I insert the accent character é in the form then I valid, it will be saved in the database as é not é as you can see in screenshot below:
Whereas when I run the code below in Symfony2:
<?php
$tab = $_REQUEST['table'];
$a = $tab[0];
$b = $tab[1];
$con=mysqli_connect("localhost","root","","wkayetdb");
if (mysqli_connect_errno()) {
echo "Failed to connect to MySQL: " . mysqli_connect_error();
}
$result = mysqli_query($con,"INSERT INTO messages(actor,subject,contenu,status,type) VALUES ($a,$b,'é','unseen','G')");
mysqli_close($con);
?>
it works correctly and the character é will be saved as é as you can see below:
So, my questions are:
What is wrong in my code?
How can I save é as é in a mysql database once it is inserted in a form in Symfony2 ?
I do not know why you want to do that
but if you want to do this, simply comment that line "charset: UTF8"
doctrine:
dbal:
driver: "%database_driver%"
host: "%database_host%"
port: "%database_port%"
dbname: "%database_name%"
user: "%database_user%"
password: "%database_password%"
# charset: UTF8
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 :)
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);