I install Doctrine Extensions like here How to install Doctrine Extensions in a Symfony2 project
This is my Entity Class
<?php
namespace My\NewsBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Gedmo\Mapping\Annotation as Gedmo;
/**
* News
*
* #ORM\Table()
* #ORM\Entity
*/
class News
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\Column(type="string", length=150)
*/
protected $title;
/**
* #ORM\Column(type="text")
*/
protected $content;
/**
* #ORM\Column(type="text")
*/
protected $description;
/**
* #ORM\Column(type="string", length=150)
*/
protected $keywords;
/**
* #Gedmo\Slug(fields={"title"})
* #ORM\Column(length=128, unique=true)
*/
private $slug;
/**
* #Gedmo\Timestampable(on="create")
* #ORM\Column(name="created_at", type="datetime")
*/
private $created_at;
/**
* #ORM\Column(name="updated_at", type="datetime")
* #Gedmo\Timestampable(on="update")
*/
private $updated_at;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
}
php app/console doctrine:generate:entities My
gives me a a error
[Doctrine\Common\Annotations\AnnotationException]
[Semantical Error] The annotation "#Gedmo\Mapping\Annotation\Slug" in property My\NewsBundle\Entity\News::$slug does not exist, or could not be auto -loaded.
Should i add something in config or someting else? Thanks for help.
Related
I am new to both Symfony and API platform and trying to understand how to get all unique brands and product types of my products in a list so that I can use them later to display a list of filters to use in my frontend.
I'm a bit lost as to how to do this. I want to have a custom endpoint products/filters that would return me the list.
I would like to have it in this form:
{
brands: [
"Agilent",
"Comtr"
"Anot
],
types:[
"Accelerometer",
"Sonometer",
"Micro-amplifier"
]
}
Both brand and type are nested properties of my entity Product, they come from my entity ProductModel. I am using Api platform for my api that is why there is a lot of annotations.
class Product
{
/**
* #ORM\Id
* #ORM\GeneratedValue
* #ORM\Column(type="integer")
* #Groups({"product_get", "product_list"})
*/
private $id;
/**
* #ORM\ManyToOne(targetEntity=ProductModel::class, cascade={"persist"})
* #ORM\JoinColumn(nullable=false)
* #Groups({"product_get", "product_list"})
*/
private $idProductModel;
/**
* #ORM\Column(type="string", length=50)
* #Groups({"product_get", "product_list"})
* #Assert\NotBlank(message="The field serial number is mandatory.")
*/
private $serialNumber;
/**
* #ORM\Column(type="text", nullable=true)
* #Groups({"product_get"})
*/
private $comment;
/**
* #ORM\Column(type="datetime")
* #Groups({"product_get", "product_list"})
*/
private $createdAt;
/**
* #ORM\Column(type="datetime", nullable=true)
* #Groups({"product_get", "product_list"})
*/
private $updatedAt;
/**
* #ORM\Column(type="datetime", nullable=true)
* #Groups({"product_get"})
*
*/
private $deletedAt;
/**
* #ORM\Column(type="boolean")
* #Groups({"product_get", "product_list"})
* #Assert\NotBlank(message="The field confidential is mandatory.")
*
*/
private $confidential;
/**
* #ORM\ManyToOne(targetEntity=Storage::class, cascade={"persist"})
* #Groups({"product_get", "product_list"})
*/
private $idStorage;
/**
* #ORM\ManyToOne(targetEntity=User::class, cascade={"persist"})
* #ORM\JoinColumn(nullable=false)
* #Groups({"product_get", "product_list"})
*/
private $idUser;
/**
* #ORM\ManyToOne(targetEntity=User::class, cascade={"persist"})
* #Groups({"product_get"})
*/
private $idUserDelete;
/**
* Many products can have many products
* #ORM\ManyToMany(targetEntity=Product::class, mappedBy="myProducts")
*/
private $partOfthisProduct;
/**
* Many products can have many products
* #ORM\ManyToMany(targetEntity=Product::class, inversedBy="partOfthisProduct")
* #JoinTable(name="product_has_product",
* joinColumns={#JoinColumn(name="product_id", referencedColumnName="id")},
* inverseJoinColumns={#JoinColumn(name="related_product_id", referencedColumnName="id")}
* )
* #Groups({"product_get", "product_list"})
*/
private $myProducts;
/**
* #ORM\OneToMany(targetEntity=Sensor::class, mappedBy="product", cascade={"persist"})
* #Groups({"product_get", "product_list"})
* #ApiSubresource()
*/
private $sensors;
<?php
namespace App\Entity;
use ApiPlatform\Core\Annotation\ApiResource;
use ApiPlatform\Core\Annotation\ApiSubresource;
use App\Repository\ProductModelRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\ORM\Mapping\ManyToMany;
use Symfony\Component\Serializer\Annotation\Groups;
use Doctrine\ORM\Mapping\JoinTable;
use Doctrine\ORM\Mapping\JoinColumn;
/**
* #ORM\Entity(repositoryClass=ProductModelRepository::class)
* #ApiResource(
* itemOperations={"get"},
* collectionOperations={"get"},
* normalizationContext={
* "groups"={"read"}}
* )
*/
class ProductModel
{
/**
* #ORM\Id
* #ORM\GeneratedValue
* #ORM\Column(type="integer")
* #Groups({"read", "product_get", "product_list"})
*/
private $id;
/**
* #ORM\Column(type="string", length=50)
* #Groups({"read", "product_get", "product_list"})
*/
private $modelName;
/**
* #ORM\ManyToOne(targetEntity=ProductType::class, cascade={"persist"})
* #ORM\JoinColumn(nullable=false)
* #Groups({"read", "product_get", "product_list"})
*/
private $idProductType;
/**
* #ORM\ManyToOne(targetEntity=Unit::class)
*/
private $idInputUnit;
/**
* #ORM\ManyToOne(targetEntity=Unit::class)
*/
private $idOutputUnit;
/**
* #ORM\ManyToOne(targetEntity=Brand::class, cascade={"persist"})
* #ORM\JoinColumn(nullable=false)
* #Groups({"read", "sensor_get", "product_list"})
*/
private $idBrand;
/**
* #ORM\ManyToMany(targetEntity=TestType::class)
* #Groups({"read", "sensor_get", "product_get"})
*/
private $idTestsTypes;
/**
* #ORM\Column(type="integer", nullable=true)
* #Groups({"read", "sensor_get"})
*/
private $periodicity;
/**
* #ORM\Column(type="float", nullable=true)
* #Groups({"read", "sensor_get", "product_get"})
*/
private $nominalSensitivity;
/**
* #ORM\ManyToOne(targetEntity=TestType::class)
* #Groups({"read", "sensor_get", "product_get"})
*/
private $periodicityTest;
/**
* Many ProductModel have Many SensorModel.
* #ManyToMany(targetEntity="SensorModel")
* #JoinTable(name="productModel_sensorModels",
* joinColumns={#JoinColumn(name="Product_model_id", referencedColumnName="id")},
* inverseJoinColumns={#JoinColumn(name="Sensor_Model_id", referencedColumnName="id", unique=true)}
* )
* #Groups({"read", "sensor_get", "product_get"})
*/
private $sensorModels;
What would be the way to do this ? Thank you for your help.
Think the best way to do it is with a custom action that calls a method from the entity's repository.
First you add a custom operation to your #ApiResource definition, in the collectionOperations part in this case.
/**
* #ApiResource(
* itemOperations={"get","put","delete"},
* collectionOperations={
* "get","post",
* "types"={
* "method"="GET",
* "path"="/product_models/brands",
* "controller"=DistinctBrandsAction::class,
* "openapi_context"={
* "parameters"={}
* },
* "read"=false,
* }
* }
* )
* #ORM\Entity(repositoryClass=Repository::class)
*/
Then you add a method to your entity's repository (it would be ProductModelRepository in your case).
This method will query the collection and get the distinct values of the desired column. You'll have to modify this a bit to get the exact output you want (add the product types etc.):
//..blah blah.. use statements etc.
class ProductModelRepository extends ServiceEntityRepository
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, Report::class);
}
//this is the method you're adding:
//for symfony 3+ you use groupBy() instead of distinct() to get distinct values for a column
public function getDistinctBrands() {
return $this->createQueryBuilder('r')
->select('r.idBrand')
->groupBy('r.idBrand')
->getQuery()
->getResult();
}
}
Then you need to create a controller for your configured action that calls the method you added to the repository and then outputs it. (This would go in src/Controller/Action/DistinctBrandsAction.php if you're using autowiring)
<?php
namespace App\Controller\Action;
use App\Entity\Report;
use App\Repository\ProductModelRepository;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
/**
* Class DistinctBrandsAction
*/
final class DistinctBrandsAction extends AbstractController
{
/**
* #param ProductModelRepository $productRepository
* #return Array
*/
public function __invoke(ProductModelRepository $productRepository): Array
{
return $productRepository->getDistinctBrands();
}
}
You can use the console to see what your resulting route is. It should be grouped with your ProductModel routes when running php bin/console debug:router
Further reading:
https://api-platform.com/docs/core/pagination/#custom-controller-action
I am using Symfony 3 and want to map Entity Userto have many BitcoinWallet
My AppBundle\Entity\User.php looks like that:
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use FOS\UserBundle\Model\User as BaseUser;
use Gedmo\Mapping\Annotation as Gedmo;
use Symfony\Component\Validator\Constraints as Assert;
/**
* #ORM\Entity
* #ORM\Table(name="user")
*/
class User extends BaseUser
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #var string
* #ORM\Column(type="string", length=255, nullable=true)
*/
protected $firstName;
/**
* #var string
* #ORM\Column(type="string", length=255, nullable=true)
*/
protected $lastName;
/**
* #ORM\Column(type="string", length=255, nullable=true)
* #Assert\File(maxSize="2048k")
* #Assert\Image(mimeTypesMessage="Please upload a valid image.")
*/
protected $profilePicture;
/**
* #Assert\Email(
* message = "The email '{{ value }}' is not a valid email.",
* checkMX = true
* )
*/
protected $email;
protected $emailCanonical;
/**
* #ORM\ManyToOne(targetEntity="BitcoinBundle\Entity\BitcoinWallet")
* #ORM\JoinColumn(name="bitcoin_wallet", referencedColumnName="id")
*/
protected $bitcoinWallet;
/**
* #var \DateTime $created
*
* #Gedmo\Timestampable(on="create")
* #ORM\Column(type="datetime")
*/
private $created;
/**
* #var \DateTime $updated
*
* #Gedmo\Timestampable(on="update")
* #ORM\Column(type="datetime")
*/
private $updated;
My BitcoinBundle\Entity\BitcoinWallet is below:
<?php
namespace BitcoinBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity(repositoryClass="BitcoinBundle\Entity\BitcoinWalletRepository")
* #ORM\Table(name="bitcoin_wallet")
* #ORM\HasLifecycleCallbacks
*/
class BitcoinWallet
{
/**
* in use = The address is being used for some reason
* available = the address is free
*/
const STATE_IN_USE = 0;
const STATE_AVAILABLE = 1;
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\Column
* #ORM\GeneratedValue(strategy="NONE")
* #ORM\Column(type="string", length=34, unique=true)
*/
private $address;
/**
* #ORM\Column(name="state", type="smallint")
*/
private $state;
/**
* #ORM\Column(name="balance", type="decimal", precision=16, scale=8)
*/
private $balance = 0;
/**
* #ORM\Column(name="updated_at", type="datetime")
*/
private $updated_at;
After I run php bin/console doctrine:schema:update --force database was updated successfully, but now I am getting this message:
The target-entity BitcoinBundle\Entity\BitcoinWallet cannot be found in 'AppBundle\Entity\User#bitcoinWallet'.
It looks like entity declaration was incorrect.
In BitcoinBundle\Entity\BitcoinWallet should be ManyToOne statment:
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
* #ORM\ManyToOne(targetEntity="UserBundle\Entity\User", inversedBy="bitcoin_wallet")
*/
protected $id;
And ManyToOne statment in AppBundle\Entity\User.php is wrong one.
I have defined two database entities
Project:
use Doctrine\ORM\Mapping as ORM;
use \Kdyby\Doctrine\Entities\MagicAccessors;
/**
* #ORM\Entity
*/
class Project extends \Kdyby\Doctrine\Entities\BaseEntity
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue
*/
public $id;
/**
* #ORM\Column(type="string")
*/
public $title;
/**
* #ORM\Column(type="text")
* #var string
*/
public $description;
/**
* #ORM\Column(type="datetime", nullable=true)
* #var DateTime
*/
public $created;
/**
* #ORM\Column(type="boolean")
* #var string
*/
public $public;
/**
* #ORM\Column(type="blob")
* #var string
*/
public $thumbnail;
public function __construct()
{
$this->created = new \DateTime();
$this->public = 0;
}
}
and Personage:
use Doctrine\ORM\Mapping as ORM;
use \Kdyby\Doctrine\Entities\MagicAccessors;
/**
* #ORM\Entity
*/
class Personage extends \Kdyby\Doctrine\Entities\BaseEntity
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue
*/
public $id;
/**
* #ORM\Column(type="string")
*/
public $name;
/**
* #ORM\Column(type="text", nullable=true)
* #var string
*/
public $shortDescription;
/**
* #ORM\Column(type="text", nullable=true)
* #var string
*/
public $playerDescription;
/**
* #ORM\Column(type="datetime")
* #var DateTime
*/
public $created;
/**
* #ORM\Column(type="integer")
* #var string
*/
public $creator;
/**
* #ORM\Column(type="boolean", options={"default" = false})
* #var boolean
*/
public $inGraph;
/**
* #ORM\Column(type="boolean", nullable=false, options={"default" = 0})
* #var boolean
*/
public $deleted;
/**
* #ORM\ManyToOne(targetEntity="Project", cascade={"persist", "remove"})
* #ORM\JoinColumn(name="project", referencedColumnName="id", onDelete="CASCADE")
* #var string
*/
public $project_id;
public function __construct()
{
$this->deleted = 0;
$this->inGraph = 0;
}
}
Every Personage entity belongs to some project. But whenever I try to remove Personage either this way:
public function removeChar($id)
{
$a = $this->EntityManager->find('App\Personage', $id);
if($a->deleted)
{
$this->EntityManager->remove($a);
$this->EntityManager->flush();
}
}
or using dql. It removes the whole project row as well. What i want is whenever project is removed it removes all characters corresponding but NOT other way around.
I tried to remove
cascade={"persist", "remove"}
part from Project entity declaration (and updating database via console) but it said everything was in sync and did nothing. So I removed whole database and build it without cascade={"persist", "remove"}, but the problem was not solved.
remove onDelete="CASCADE" from
#ORM\JoinColumn(name="project", referencedColumnName="id", onDelete="CASCADE")
and add
#ORM\OneToMany(targetEntity="Personage", mappedBy="project_id",cascade={"remove"})
private $personages;
in the project entity.
I'm trying to create a "OneToMany" bidirectional association in my project but when I execute "doctrine:schema:update" nothing happens.
If I create this association directly from Sequel Pro and run the update schema command, that changes dissapear... :/
The relations is:
- One "id" from Customers Table with many "customer_id" form Control table.
Here is the Customers code:
<?php
namespace Ourentec\CustomersBundle\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
/**
* Customers
*
* #ORM\Table()
* #ORM\Entity
*/
class Customers
{
/* #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=100)
*/
private $name;
/**
* #var string
*
* #ORM\Column(name="lastname", type="string", length=100)
*/
private $lastname;
/**
* #var string
*
* #ORM\Column(name="address", type="text")
*/
private $address;
/**
* #var string
*
* #ORM\Column(name="phone", type="string", length=100)
*/
private $phone;
/**
* #var string
*
* #ORM\Column(name="pass", type="string", length=100)
*/
private $pass;
/**
* #var string
*
* #ORM\Column(name="tasks", type="text")
*/
private $tasks;
/**
* #var string
*
* #ORM\Column(name="status", type="string", length=100)
*/
private $status;
/**
* #var string
*
* #ORM\Column(name="email", type="string", length=100)
*/
private $email;
/**
* #var \DateTime
*
* #ORM\Column(name="date", type="datetime")
*/
private $date;
/**
* #var string
*
* #ORM\Column(name="location", type="string", length=100)
*/
private $location;
/**
* #ORM\OneToMany(targetEntity="Control", mappedBy="customers")
*/
private $customer_id;
public function __construct()
{
$this->customer_id = new ArrayCollection();
}
And the Control code:
<?php
namespace Ourentec\CustomersBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Control
*
* #ORM\Table()
* #ORM\Entity
*/
class Control
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var integer
*
* #ORM\Column(name="customer_id", type="integer")
*
* #ORM\ManyToOne(targetEntity="Customers", inversedBy="control")
* #ORM\JoinColumn(name="customer_id", referencedColumnName="id")
*/
private $customerId;
/**
* #var integer
*
* #ORM\Column(name="user_id", type="integer")
*/
private $userId;
/**
* #var \DateTime
*
* #ORM\Column(name="date", type="datetime")
*/
private $date;
/**
* #var integer
*
* #ORM\Column(name="seen", type="smallint")
*/
private $seen;
I followed the documentation from this 2 websites
http://symfony.com/doc/current/book/doctrine.html
http://librosweb.es/libro/symfony_2_x/capitulo_8/relaciones_y_asociaciones_de_entidades.html
But I don't know why it does not work..
Any idea will be appreciated :)
Mapping are not correct, I will try to explain how it works.
In Customers entity (you should rename it to Customer, entites names are singular)
/**
* #ORM\OneToMany(targetEntity="Control", mappedBy="customer")
*/
private $controls;
Mapped by option defines field name in the other entity.
/**
* #var integer
*
* #ORM\Column(name="customer_id", type="integer")
*
* #ORM\ManyToOne(targetEntity="Customers", inversedBy="controls")
* #ORM\JoinColumn(name="customer_id", referencedColumnName="id")
*/
private $customer;
Same thing with inversedBy.
In Customers entity you also need to init controls var as an ArrayCollection:
public function __construct()
{
$this->controls = new ArrayCollection();
}
With these mappings schema should be updated correctly.
For more info, check doctrine docs.
I have businesses, categories and products. Categories are assigned to businesses and products are assigned to categories and businesses.
Reason being, one product can be assigned to different categories in different businesses.
Business and Category entities are working fine, but I am not sure how to write a Product entity to achieve what I need...
Business Entity:
namespace Raiel\AFMage\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity()
* #ORM\Table(name="businesses")
*/
class Business {
/**
* #ORM\Id()
* #ORM\GeneratedValue(strategy="AUTO")
* #ORM\Column(type="integer", name="id")
*/
private $id;
/**
* #ORM\Column(name="name", type="string", length=64)
*/
private $name;
/**
*
* #ORM\ManyToMany(targetEntity="Category", inversedBy="businesses")
* #ORM\JoinTable(
* name="business_categories",
* joinColumns={
* #ORM\JoinColumn(name="business_id", referencedColumnName="id")
* },
* inverseJoinColumns={
* #ORM\JoinColumn(name="category_id", referencedColumnName="id")
* }
* )
*/
private $categories;
/**
* Default constructor, initializes collections
*/
public function __construct() {
$this->categories = new ArrayCollection();
}
}
Category Entity:
<?php
namespace Raiel\AFMage\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
use Gedmo\Mapping\Annotation as Gedmo;
/**
* #Gedmo\Tree(type="nested")
* #ORM\Table(name="categories")
* #ORM\Entity(repositoryClass="Gedmo\Tree\Entity\Repository\NestedTreeRepository")
*/
class Category {
/**
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue
*/
private $id;
/**
*
* #ORM\ManyToMany(targetEntity="Business", mappedBy="categories")
*/
private $businesses;
/**
* #Gedmo\TreePath
* #ORM\Column(name="path", type="string", length=3000, nullable=true)
*/
private $path;
/**
* #ORM\Column(name="title", type="string", length=64)
*/
private $title;
/**
* #Gedmo\TreeLevel
* #ORM\Column(name="lvl", type="integer")
*/
private $lvl;
/**
* #Gedmo\TreeLeft
* #ORM\Column(name="lft", type="integer")
*/
private $lft;
/**
* #Gedmo\TreeRight
* #ORM\Column(name="rgt", type="integer")
*/
private $rgt;
/**
* #Gedmo\TreeRoot
* #ORM\Column(name="root", type="integer", nullable=true)
*/
private $root;
/**
* #Gedmo\TreeParent
* #ORM\ManyToOne(targetEntity="Category", inversedBy="children")
* #ORM\JoinColumn(name="parent_id", referencedColumnName="id", onDelete="CASCADE")
*/
private $parent;
/**
* #ORM\OneToMany(targetEntity="Category", mappedBy="parent")
* #ORM\OrderBy({"lft" = "ASC"})
*/
private $children;
/**
* Constructor
*/
public function __construct() {
$this->children = new ArrayCollection();
$this->businesses = new ArrayCollection();
}
}
Also, $business->addCategory works fine but $category->addBusiness doesn't save to DB.
Your product entity will probably look something like:
namespace Raiel\AFMage\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity()
* #ORM\Table(name="products")
*/
class Product {
/**
* #ORM\Id()
* #ORM\GeneratedValue(strategy="AUTO")
* #ORM\Column(type="integer", name="id")
*/
private $id;
/**
* #ORM\Column(name="name", type="string", length=64)
*/
private $name;
/**
*
* #ORM\ManyToMany(targetEntity="Category", inversedBy="products")
* #ORM\JoinTable(
* name="product_categories",
* joinColumns={
* #ORM\JoinColumn(name="product_id", referencedColumnName="id")
* },
* inverseJoinColumns={
* #ORM\JoinColumn(name="category_id", referencedColumnName="id")
* }
* )
*/
private $categories;
/**
*
* #ORM\ManyToMany(targetEntity="Business", inversedBy="products")
* #ORM\JoinTable(
* name="product_businesses",
* joinColumns={
* #ORM\JoinColumn(name="product_id", referencedColumnName="id")
* },
* inverseJoinColumns={
* #ORM\JoinColumn(name="business_id", referencedColumnName="id")
* }
* )
*/
private $businesses;
}
So more or less what you have for your Business entity but with the ManyToMany relation using a different join table.
And to make $category->addBusiness() work then you'll probably want to add a cascade option to category, thusly:
/**
*
* #ORM\ManyToMany(targetEntity="Business", mappedBy="categories", cascade="persist")
*/
private $businesses;
This informs Doctrine that anything new added to the $businesses array collection should be persisted, take a look at the documentation for details.