Add refrences to MongoDB schema within Symfony project - mongodb

I'm trying to create MongoDB database with some references within Symfony.
In my context I have 2 documents Customer and Meeting, One Customer can have Many Meeting so that what I did :
Meeting.php
<?php
namespace FrontOfficeBundle\Document;
use Doctrine\ODM\MongoDB\Mapping\Annotations as MongoDB;
/**
* #MongoDB\Document
*/
class Meeting
{
/**
* #MongoDB\Id
* #MongoDB\ReferenceOne(targetDocument="Customer")
*/
protected $id;
/**
* #MongoDB\Field(type="timestamp")
*/
protected $creationDate;
...
Customer.php
<?php
namespace FrontOfficeBundle\Document;
use Doctrine\ODM\MongoDB\Mapping\Annotations as MongoDB;
/**
* #MongoDB\Document
*/
class Customer
{
/**
* #MongoDB\Id()
* #MongoDB\ReferenceMany(targetDocument="Meeting")
*/
protected $id;
/**
* #MongoDB\Field(type="string")
*/
protected $username;
...
and then when I run the command line:
php bin/console doctrine:mongodb:schema:update
I got :
No identifier/primary key specified for Document 'FrontOfficeBundle\Document\Meeting'. Every Document must have an identifier/primary key.
I tried by using #MongoDB\UniqueIndex() but no way.
I think that #MongoDB\Id is supposed as an identifier !!!
Versions
Symfony 3.2
MongoDB 3.4.4
Any ideas ?
Thanks you.

Finally I found a solution, first I added a field called $meetings in the document Customer and an other $customer in the document meeting like this :
Customer.php
/**
* #MongoDB\ReferenceMany(targetDocument="meeting", mappedBy="customer")
*/
protected $meetings;
Meeting.php
/**
* #MongoDB\ReferenceOne(targetDocument="customer", inversedBy="meetings")
*/
protected $customer;
Then run the command line to generate setters and getters:
php bin/console doctrine:mongodb:generate:documents mybundleBundle
And when I run a fixtures (Creating one customer then its meeting), everything work fine, you'll notice that the relationship 1 to many has been defined in your document (I'm using compass to display mongoDB) as a One-to-Squillions model (for more details about 1-to-N relationship : (https://www.mongodb.com/blog/post/6-rules-of-thumb-for-mongodb-schema-design-part-1) that's mean the son document (meeting) contains the reference of the parent as shown below :
Customer
Meeting
In MongoDB the #MongDB/Id is a primary key and the foreign key and never try to define references to this unique field.
Thanks for your attention.

Related

Doctrine and MongoDb: Define required fields in MongoDb-Document (

I'm using MongoDB with Doctrine for a Symfony project.
For a document (I call it class Product) I need to define a field (e.g. name), but I want to act doctrine in a way that the document cannot be saved without defining a it. Meaning, whenever creating or updating a new Product, the property $name has to be defined.
For doctrine and MySql this is quite simple. There you have to say:
class Product {
...
/** #ORM\Column(type="string", nullable=false) */
private $name;
...
}
Is there a similar way in MongoDb?
The following code (which I found in a similar thread) doesn't work:
class Product {
...
/**
* #MongoDB\Field(type="string")
* #Constraints\NotBlank
*/
protected $name;
...
}

Persisting a document suddenly stops returning next identifier value (ALNUM strategry)

I have Symfony 2.6 application and using doctrine-odm-bundle 3.0.2 (doctrine-odm: 1.1.2, mongodb: 1.4.0).
My document has referenceMany and referenceOne in attributes and when I create new instance of it, fill fields and persist - it goes fine in the begining. I can create few nearly empty documents, with referenced document(s) or without and it works fine. At some point I am trying to add new item in the database and getting an error:
E11000 duplicate key error collection: test.Product index: _id_ dup key: { : 0 }
The message is clear - I can see that there was a document added to the collection with id = 0, therefore second one can't go -> duplicate entry. But why it suddenly starts to return "0" for id? Even though, I checked doctrine_increment_ids collection - counter for id is being incremented. But $product->getId() becomes "0" after persist.
If I drop the database and start all over - it works, I can still add new products in the collection. Let's say I successfully created 12 products. Creating 13th resulting a document with id=0 being persisted in the collection. 14th fails with duplicate error.
Can you please help to troubleshoot or suggest an idea where does it go wrong?
P.S> I am not considering an upgrade of Symfony2 (at this point) neither as doctrine-odm-bundle (it depends on newer Symfony2 as well) - migration efforts are quite high and I am not sure it will fix the issue. First I want to find out the root cause.
// Document Product
/**
* #MongoDB\Document
* #MongoDB\HasLifecycleCallbacks
*/
class Product
{
/** #MongoDB\Id(strategy="ALNUM", type="int") */
protected $id;
/**
* #Gedmo\ReferenceOne(type="entity", class="Entity\User", inversedBy="products", identifier="userId")
*/
protected $user;
/**
* #MongoDB\Field(name="user_id", type="int")
*/
protected $userId;
/**
* #MongoDB\ReferenceMany(
* targetDocument="Picture",
* discriminatorMap={"file" = "File", "picture" = "Picture"},
* discriminatorField="discr",
* defaultDiscriminatorValue="picture"
* )
* #Assert\Valid
*/
protected $pictures;
...
}
// Entity User
/**
* User entity
* #ORM\Entity
* #ORM\Table(name="users")
*/
class User
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #var ArrayCollection $textures
*
* #Gedmo\ReferenceMany(type="document", class="Document\Product", mappedBy="user")
*/
protected $products;
...
}
// Document Picture
/**
* #MongoDB\Document
* #MongoDB\InheritanceType("SINGLE_COLLECTION")
* #MongoDB\DiscriminatorField("discr")
* #MongoDB\DiscriminatorMap({"file" = "File", "picture" = "Picture"})
* #MongoDB\DefaultDiscriminatorValue("picture")
* #MongoDB\HasLifecycleCallbacks
*/
class Picture
{
/**
*
* #MongoDB\Id(strategy="ALNUM", type="int")
*/
protected $id;
/**
* #MongoDB\ReferenceOne(targetDocument="Product")
*
* #var Product $product
*/
protected $product;
...
}
Documentation reading always helps (generation strategies). Basically, strategy="ALNUM" and type="int" just can't go together :)
Change strategy to INCREMENT and remove type="int" if you want to have integers in your _id.
Or you can change type to string to continue with _id being an alphanumeric string.

How to add Field to a mongoDB database in a Symfony2/SonataAdmin project?

I'm working in a BackOffice Symfony2.3 with MongoDB and SonataAdmin.
I'm trying to add a new field to one of the documents.
I've just added one parameter
/**
* #var integer
* #MongoDB\Int
*/
protected $price_teste;
I used the console to add the getters and the setters in the class.
Finally, I've changed the admin class in sonata to have in the form the new champ
/**
* #param ListMapper $listMapper
*/
protected function configureListFields(ListMapper $listMapper)
{
$listMapper
//...
->add('price_teste')
//....
When I go to the BackOffice I see the new champ but when I try to update the instance, the value disappears. So I imagine it's not being persisted to the database.
There any other procedure I'm forgetting to do to add a new parameter to an existing document in the project?

How to get the type of MongoDB Document in twig?

I used Symfony2 and Doctrine MongoDBBundle and I have simple Single Collection Inheritance classes. How can I know what type of document it is in a twig template? For example the base class is Entity and extended by User and Organization, in listing those in a twig template I'd like to know what type of entity it is (i.e. whether it's a User or an Organization). I wonder if it's possible to get the value of the DiscriminatorField of the document.
/**
* #MongoDB\Document(collection="entity")
* #MongoDB\InheritanceType("SINGLE_COLLECTION")
* #MongoDB\DiscriminatorField(fieldName="type")
* #MongoDB\DiscriminatorMap({"user"="User", "shop"="Shop"})
*/
class Entity
{
/**
* #MongoDB\Id
*/
protected $id;
protected $entityType;
public function getEntityType()
{
return $this->entityType;
}
}

Symfony2 form and Doctrine OneToOne relationship

I have 2 entities: User and Avatar. Each user can choice one avatar from a list, so I think this is a One2One unidirectional relationship. The problem is that the field avatar_id is always NULL in the db when I save the form.
Let's see the code:
class User implements UserInterface
{
/**
* #var int $avatarId
*
* #ORM\Column(name="avatar_id", type="integer", nullable=true)
*/
private $avatarId;
/**
* #var Avatar
*
* #ORM\OneToOne(targetEntity="Avatar", cascade={"persist", "remove"})
*/
private $avatar;
}
When I var_dump the user object before saving, the field avatarId contains the Avatar object but the id is not saved. What I'm doing wrong?
["avatarId":"Test\UserBundle\Entity\User":private]=>
object(Test\UserBundle\Entity\Avatar)#419 (5) {
["id":"Test\User\Bundle\Entity\Avatar":private]=>
int(3)
["imageName":"Test\UserBundle\Entity\Avatar":private]=>
string(14) "death-dark.jpg"
}
You don't need the avatarId field, since the avatar field will take care of it automatically. You can use the #JoinColumn annotation to set the referencing column name explicitly.
A few things:
ID columns are typically generated with the following annotations:
/**
* #ORM\Id #ORM\Column(type="integer")
* #ORM\GeneratedValue
*/
This tells the ORM to automatically generate a value when you create a new object, thus when you dump the object it will have a value before persisting.
And a note on your OneToOne relationship, if Avatars can be used by multiple people from that list, that would be a ManyToOne relationship (Many users to one avatar, one avatar to many users).