i have a bundle CompanyBundle with:
a class Product with this inside
/**
* #ORM\ManyToMany(targetEntity="CompanyBundle\Entity\ProductImage", inversedBy="listProduct")
**/
private $listProductImage;
and a class ProductImage having this:
/**
* #ORM\ManyToMany(targetEntity="CompanyBundle\Entity\Product", mappedBy="listProductImage")
*/
private $listProduct;
but i also extend my class Product from another ClinetBundle like that:
/**
* #ORM\Entity(repositoryClass="ClientBundle\Entity\Repository\ClientProductRepository")
*/
class ClientProduct extends Product
{
/**
* #ORM\ManyToMany(targetEntity="ClientBundle\Entity\ClientProductImage", inversedBy="listProduct")
**/
private $listProductImage;
}
but when in my controller i build a ClientProduct object class and that i try to access to the ClientProductImage from it, it is giving the class from the CompanyBundle, not the ClientBundle. so, how can i do to get the ProductImage from the ClientBundle?
it is like if my /** #ORM\ManyToMany(targetEntity="ClientBundle\Entity\ClientProductImage", inversedBy="listProduct") **/ was doing nothing :(
thanks for your help!
I finally found the solution.
I don't keep the useless relation defined in ClientProduct.
so i deleted the ManyToMany(targetEntity="ClientBundle\Entity\ClientProductImage"
and after that, i opened my app/config.yml and add the resolve_target_entities:
doctrine:
...
orm:
...
resolve_target_entities:
CompanyBundle\Entity\ProductImage: ClientBundle\Entity\ClientProductImage
all work fine, and i don't need to change the CompanyBundle :)
Related
I got a Cours (it's french for lesson) entity, and this entity have a "prof" attribute that is a manytoone relation with a Prof (teacher in french) entity. This Prof entity in itself extend an Eleve (student) entity (a prof is an eleve with more attributes and methods).
I created a prof and a cours with fixtures, just to test my app. Then, in a CourseController, I tried to send my cours and prof informations to a view. To do so, I load my cours, then I try to access my prof through my cours.
When I try to show the cours informations, everything is fine. But when I try to access the prof, nothing works anymore. I got an error that tells me that id column doesn't exists, and when I try to dump the prof, it tells me isInitialized is false, and every attributes is null.
I found other stackoverflow (or other forums) topics with similar problems where people explain that symfony do lazy loading, and doesn't load the related entity this way it gets faster. But all solutions proposed doesn't work or aren't good choices in my case.
One of the solution seems to be to set fetching to eager in my manytoone relation. But the problem is that prof itself has many manytoone or manytomany or other relations, and each of this entities has to allow access to entities related (so fetching eager too), and so, each time I'll want to get an entity, I'll load the entire database. And I just want to load what I need, which will change in each controller and each methods.
Another solution proposed is to call some methods of my related object (prof in this situation), to tell doctrine we need to access it, this way doctrine load it. But this result with the exception again (telling id column is not found).
in CoursController :
/**
* #Route("/cours/{slug}", name="presentationCours")
*/
public function presentationCours(Cours $cours)
{
$prof = $cours->getProf();
// $prof->getLogin(); THIS result with exception
dump($prof); // THIS shows all null values
die();
return $this->render('cours/presentation.html.twig', [
"cours" => $cours,
"prof" => $prof
]);
}
note : if you wonder how I get the $cours var without telling symfony where to find it, it can find it just with the slug in the route. It's new in symfony 4 (not sure it's new but I think). I'm sure it works, I did it many times and a dump($cours) perfectly works.
the twig file :
{% extends 'base.html.twig' %}
{% block title %}{{ cours.nom }}{% endblock %}
{% block body %}
<p>
{{ cours.nom }}
</p>
<p>
{{ cours.description }}
</p>
<p>
{{ prof.login }} {# THIS result with exception #}
</p>
{% endblock %}
part of the Eleve entity (the entity which is parent of prof : prof extends eleve)
<?php
namespace App\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity(repositoryClass="App\Repository\EleveRepository")
*/
class Eleve
{
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="string", length=255)
*/
private $login;
...
}
part of the prof entity :
<?php
namespace App\Entity;
use App\Entity\Eleve;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity(repositoryClass="App\Repository\ProfRepository")
*/
class Prof extends Eleve
{
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\Column(type="text")
*/
private $introduction;
/**
* #ORM\Column(type="text")
*/
private $description;
/**
* #ORM\OneToMany(targetEntity="App\Entity\Cours", mappedBy="prof")
*/
private $cours;
part of the cours entity :
<?php
namespace App\Entity;
use Cocur\Slugify\Slugify;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\Collection;
use Doctrine\Common\Collections\ArrayCollection;
/**
* #ORM\Entity(repositoryClass="App\Repository\CoursRepository")
* #ORM\HasLifecycleCallbacks
*/
class Cours
{
/**
* #ORM\Id()
* #ORM\GeneratedValue()
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\ManyToOne(targetEntity="App\Entity\Prof", inversedBy="cours")
* #ORM\JoinColumn(nullable=false)
*/
private $prof;
in the database with phpmyadmin :
part of the cours table :
part of the prof table :
the exception (without the dump) :
the dump(prof) result :
Thank you for your time.
EDIT
Problem solved ! As jeroen told, the problem was about inheritance.
Here is what I did to manage to solve it :
<?php
namespace App\Entity;
use App\Entity\Prof;
use App\Entity\Eleve;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\ORM\Mapping\InheritanceType;
use Doctrine\ORM\Mapping\DiscriminatorMap;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping\DiscriminatorColumn;
use Doctrine\Common\Collections\ArrayCollection;
/**
* #ORM\Entity(repositoryClass="App\Repository\EleveRepository")
* #InheritanceType("SINGLE_TABLE")
* #DiscriminatorColumn(name="discr", type="string")
* #DiscriminatorMap({"eleve" = "Eleve", "prof" = "Prof"})
*/
class Eleve
{
I added the lines inheritancetype, discriminatorcolumn, and discriminatormap. This, because I chosed the class table inheritance, but you could chose the mapped superclass solution, or the single table inheritance solution.
For those who, like me, would have made a migration before changing the classes, I had a problem when I added the class table inheritance. Doctrine refused to migrate after that, an exception told me there was a foreign key problem. I'm not sure this is the good way, but I deleted my migration files in symfony (src > migrations), I droped my whole database in phpmyadmin, then in symfony, using CLI (command line interface, ctrl + รน on windows and ctrl + ` on mac (on the left of enter on the keyboard), I did :
bin/console doctrine:database:create
bin/console make:migration
bin/console doctrine:migrations:migrate
and the problem is now solved. But again, I'm really not sure this is the good way, just saying it worked for me.
Suppose I have two bundles: a FormBundle and an AccommodationBundle. These bundles I would like to Open Source independently from each other.
FormBundle i.e. has a class FormEvent
class FormEvent {
/**
* #ORM\ManyToMany(
* targetEntity="Visit",
* mappedBy="formEvents",
* cascade={"persist","remove"})
**/
protected $visits;
}
Now as you may understand, the Visit-entity is part of the AccommodationBundle.
How do I make the property visits part of the FormEvent class, only if the AccommodationBundle is registered? Do I need to extend the class FormEvent in the AccommodationBundle?
I am try to use OneupUploaderBundle for uploading files. I read the documentation of this bundle many times but I did not manage to find any simple example of an entity for the file to be uploaded. My expectation is a class definition similar to the VichUploaderBundle:
<?php
namespace Minn\AdsBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\HttpFoundation\File\File;
use Symfony\Component\Validator\Constraints as Assert;
use Vich\UploaderBundle\Mapping\Annotation as Vich;
/**
* #ORM\Entity
* #Vich\Uploadable
*/
class MotorsAdsFile {
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
public $id;
/**
* #Assert\File(
* maxSize="5M",
* mimeTypes={"image/png", "image/jpeg"}
* )
* #Vich\UploadableField(mapping="motors_files", fileNameProperty="filename")
* note: This is not a mapped field of entity metadata, just a simple property.
* #var File $file
*/
protected $file;
/**
* #ORM\Column(type="string", length=255, name="filename")
* #var string $filename
*/
protected $filename;
/**
* #ORM\Column(type="string", length=255, name="name")
* #var string $name
*/
protected $name;
// ...
}
Hope my question is clear...
I am really interested by this bundle since it supports jQuery.
Thanks,
There is no such thing as a predefined entity or ORM-handling. This has several reasons. This bundle can not foresee the projects need in terms of upload logic. If someone wants to store files to the database or not is entirely their own choice and should not be forced by a third party bundle. The thing the OneupUploaderBundle provides is a backend for the most common frontend uploaders there are.
Disclaimer: I've shorty copied and extended an answer that was already present in the GitHub issue tracker of this bundle. There you'll find quite a lot of insights on how and why this bundle is what it is now.
Given that you have already installed a working Symfony2 project, follow the installation instructions of the this bundle. I think step 1 and 2 should not be a problem, so lets hook directly to step 3, the configuration.
You said, you tried to integrate the jQuery File Uploader, so lets create a mapping for it.
Open the file app/config/config.yml and add the following lines to the end of it.
oneup_uploader:
mappings:
gallery:
frontend: blueimp
And of course, don't forget to add the following lines to app/config/routing.yml.
oneup_uploader:
resource: .
type: uploader
So much for the configuration. For the sake of simplicity we will alter the AcmeDemoBundle.
Open the file src/Acme/DemoBundle/Resources/views/Welcome/index.html.twig and delete everything between {% block content %} and {% endblock %}. We don't need this anymore.
Now insert the following:
<script type="text/javascript" src="http://code.jquery.com/jquery-1.10.2.min.js"></script>
<script type="text/javascript" src="https://rawgithub.com/blueimp/jQuery-File-Upload/master/js/vendor/jquery.ui.widget.js"></script>
<script type="text/javascript" src="https://rawgithub.com/blueimp/jQuery-File-Upload/master/js/jquery.iframe-transport.js"></script>
<script type="text/javascript" src="https://rawgithub.com/blueimp/jQuery-File-Upload/master/js/jquery.fileupload.js"></script>
<script type="text/javascript">
$(document).ready(function() {
$('#fileupload').fileupload({});
});
</script>
<input id="fileupload" type="file" name="files[]" data-url="{{ oneup_uploader_endpoint('gallery') }}" multiple />
Point your browser to the root directory of this application (app_dev.php). You'll see an input field just like expected and you can now upload some images (for example). The files will be stored in web/uploads/gallery every single one with a unique filename. Note that we used some CDNs to serve the JavaScript files needed for this.
At this point, you already have a working upload form. But besides uploading files to the uploads directory, it does nothing.
This is where the Next step section in the documentation comes in handy.
As I understand your question, you want to create an entity which stores a file path of a related file in it.
To do so, create your Entity class including all required fields.
<?php
namespace Minn\AdsBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
*/
class MotorsAdsFile {
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
public $id;
/**
* #ORM\Column(type="string", length=255, name="filename")
* #var string $filename
*/
protected $filename;
// ...
}
Then create an EventListener as described in the documentation of this bundle.
<?php
namespace Acme\HelloBundle\EventListener;
use Oneup\UploaderBundle\Event\PostPersistEvent;
use Minn\AdsBundle\Entity\MotorsAdsFile;
class UploadListener
{
protected $manager;
public function __construct(EntityManager $manager)
{
$this->manager = $manager;
}
public function onUpload(PostPersistEvent $event)
{
$file = $event->getFile();
$object = new MotorsAdsFile();
$object->setFilename($file->getPathName());
$this->manager->persist($object);
$this->manager->flush();
}
}
And of course register your event listener.
<services>
<service id="acme_hello.upload_listener" class="Acme\HelloBundle\EventListener\UploadListener">
<argument type="service" id="doctrine.orm.entity_manager" />
<tag name="kernel.event_listener" event="oneup_uploader.post_persist" method="onUpload" />
</service>
</services>
At this point the EventListener will be called as soon as a new file was uploaded through the configured mapping.
It takes this file, creates a new object of MotorsAdsFile and stores the file path to the filename property, persists and flushes it to the underlying database.
As I can't predict your actual logic, this is the most basic example I can think of. You're of course free to do whatever is needed in the event listener. (In case you need to store this object to another entity or the like.)
You'll find a bunch of other topics in the Next steps section of the documentation. For example how you'd change the naming strategy of the uploaded files or how to enable chunked uploads in case you need to upload big files.
I've a custom User Class which extends from the FOSUser Model:
use FOS\UserBundle\Model\User as BaseUser;
use JMS\Serializer\Annotation\ExclusionPolicy;
use JMS\Serializer\Annotation\Expose;
/**
* #ExclusionPolicy("all")
*/
class User extends BaseUser
My problem is: The Abstract properties from the FOSUser Model are exposed, but the properties in the custom extended class not.
To expose the properties I've two yaml files:
1) MyBundle/../Resources/config/serializer/fos/Model.User.yml
2) SecurityBundle/../Resource/config/serializer/Entity.User.yml
My custom User class has a property $name. Which should be exposed by my .yaml file:
ErwineEberhard\SecurityBundle\Entity\User:
exclusion_policy: none
properties:
name:
expose: true
groups: [list, details]
Doctrine compels me to add a $id in the exteded class. The $id is only exposed when I add * #ExclusionPolicy("all") in my custom User class.
When I add #Expose to name, no differences.
How to accomplish this?
I'm looking for a global configuration for a routing prefix. There are a number of different bundles and I need a path to the backend controllers.
/**
* #Route("/admin/post")
*/
class PostAdminController extends Controller {
}
When I configure it that way, I have to edit a lot of files, if the prefix should be changed. Is it possible, to use a variable or a filter?
/**
* #Route("/%BACKEND_PREFIX%/post")
*/
class PostAdminController extends Controller {
}
Somewhere in configuration:
backend_prefix = admin
Ok, now I found a solution, but it seems working since version 2.1.
http://symfony.com/doc/current/cookbook/routing/service_container_parameters.html