I noticed FOSUserBundle does not create any indexes.
We are supposed to create a user Document like this:
use FOS\UserBundle\Document\User as BaseUser;
use Doctrine\ODM\MongoDB\Mapping\Annotations as MongoDB;
/**
* #MongoDB\Document
*/
class User extends BaseUser
{
/**
* #MongoDB\Id(strategy="auto")
*/
protected $id;
/*
public function __construct()
{
parent::__construct();
// your own logic
}
*/
}
So how do I add an index to say, the 'email' field? Should I just overwrite the inherited attribute?
Actually FOSUserBundle does create. You should run
php app\console doctrine:mongodb:schema:update
to create them. By default there is usernameCanonical and emailCanonical indexes.
If you need custom index use this approach:
<?php
/**
* #MongoDB\Document
* #MongoDB\Indexes({
* #MongoDB\Index(keys={"email"="asc"})
* })
*/
class User extends BaseUser {
// ...
and do not forget to run doctirne:mongodb:schema:update task again.
Related
I am facing an error with symfony and mongoDB odm on one to one relationship
for example i have a user that has Work .
User Class:
/**
* #MongoDB\Document
* #MongoDBUnique(fields="email")
*/
class User implements UserInterface
{
/**
* #MongoDB\Id
*/
private $id;
/**
* #MongoDB\Field(type="string")
*/
private $firstName;
/**
* #MongoDB\Field(type="string")
*/
private $lastName;
/**
* #MongoDB\Field(type="string")
* #Assert\NotBlank()
* #Assert\Email()
*/
private $email;
/**
* #MongoDB\ReferenceOne(targetDocument=Work::class)
*/
private $work;
//getter setter
Work Class:
class Work
{
/**
* #MongoDB\Id()
*/
private $id;
/**
* #MongoDB\ReferenceOne(targetDocument=User::class)
*/
private $user;
//getter setter
}
Controller:
class TestingController extends AbstractController
{
/**
* #Route("/testing", name="testing")
* #param DocumentManager $documentManager
* #return Response
* #throws MongoDBException
*/
public function index(DocumentManager $documentManager)
{
$user = new User();
$user->setFirstName('test1');
$user->setLastName('test2');
$user->setEmail('test123#gmail.com');
$documentManager->persist($user);
$work= new Work();
$work->setUser($user);
$documentManager->persist($work);
$documentManager->flush();
return new Response("test");
}
/**
* #Route("/test", name="test")
* #param DocumentManager $documentManager
* #return Response
*/
public function test(DocumentManager $documentManager){
$user = $documentManager->getRepository(User::class)->findAll();
dump($user);
return new Response("test test");
}
}
So I created 2 classes one as user that has one work, I created the user , then I created a work and i assigned the user from the work class.
in MongoDB compass I got under Work collection a reference for the user.
now in the test method in the controller i try to find the users and dump the data.
The problem is whenever i want to find $user->getWork() i get a null value, while the user exists. but the inverse is working fine . whenever i try $work->getUser() i can find the user.
is there anything wrong in my code ? I want to use both methods : $user->getWork() and $work->getUser(),
I have tried adding to the ReferenceOne mappedBy and inversedBy but its always one of the two methods returns null value.
I think you forgot the mappedBy and inversedBy arguments in the annotation. See the documentation: https://www.doctrine-project.org/projects/doctrine-mongodb-odm/en/2.1/reference/bidirectional-references.html#one-to-one
I'm new to zend3, and I came across a problem, getservicelocator no longer exists in version 3, I'm working with a controller, I wanted to know how to implement this migration, Anyone know how to make this change
namespace Base\Controller;
use Zend\Mvc\Controller\AbstractActionController;
use Zend\View\Model\ViewModel;
use Zend\Paginator\Paginator;
use Zend\Paginator\Adapter\ArrayAdapter;
abstract class AbstractController extends AbstractActionController
{
/**
* Entity manager
* #var
*/
protected $em;
/** Entity
* #var
*/
protected $entity;
/**
* Controller
* #var
*/
protected $controller;
/**
* #var
*/
protected $route;
/**
* #var
*/
protected $service;
/**
* #var
*/
protected $form;
private $configTable;
/**
* AbstractController constructor.
*/
abstract function __construct();
...
/**
*
* #return \Zend\Http\Response
*/
public function excluirAction()
{
$service = $this->getServiceLocator()->get($this->service);
$id = $this->params()->fromRoute('id',0);
// Abstract service
if ($service->remove(array('id' => $id))) {
$this->flashMessenger()->addSuccessMessage('Success');
} else {
$this->flashMessenger()->addErrorMessage('Error');
}
return $this->redirect()->toRoute($this->route, array('controller' => $this->controller));
}
The architecture is not really good in your case, why would you have an action in an abstract controller...
The right way would be for the controller not to be abstract and pass the service through the constructor.
The wrong way would be to inject the service locator using a delegator.
The idea of removing the service locator is to be clearer on the dependencies of the class, so the code is way more readable (like "oh, I see this class needs ... and ... to do NAME_OF_THE_ACTION").
Also, it highly improve the code testability (you know what dependencies to mock/fake).
I'm trying to implement a plugin to add sales representative data to my shop and associate this data to users.
On this context (users and sales representative) I have:
sales_rep - Sales representative table
sales_rep_user - Relation between User and Sales Representative
1st For the swg_sales_rep and swg_sales_rep_user relation (OneToMany) I could create that without problems
SwgSalesRepresentative.php
...
**
* #ORM\Entity
* #ORM\Table(name="swg_sales_rep")
*/
class SwgSalesRepresentative extends ModelEntity
{
...
/**
* INVERSE SIDE
*
* #var \Doctrine\Common\Collections\ArrayCollection
*
* #ORM\OneToMany(
* targetEntity="Shopware\CustomModels\SwagUserSalesRepresentative\SwgSalesRepresentative",
* mappedBy="salesRepresentative",
* orphanRemoval=true
* )
*/
protected $salesRepresentativeUsers;
...
SwgSalesRepresentativeUsers.php
/**
* #ORM\Entity
* #ORM\Table(name="swg_sales_rep_users")
*/
class SwgSalesRepresentativeUsers extends ModelEntity
{
...
/**
*
* #ORM\ManyToOne(targetEntity="Shopware\CustomModels\SwagUserSalesRepresentative\SwgSalesRepresentative")
* #ORM\JoinColumn(name="sales_rep_id", referencedColumnName="id")
*/
protected $salesRepresentative;
/**
* #return mixed
*/
public function getSalesRepresentative()
{
return $this->salesRepresentative;
}
/**
* #param $salesRepresentative
* #return ModelEntity
*/
public function setSalesRepresentative($salesRepresentative)
{
return $this->setManyToOne(
$salesRepresentative,
'\Shopware\CustomModels\SwagUserSalesRepresentative\SwgSalesRepresentative',
'salesRepresentativeUsers'
);
}
And after install I get my tables with foreign key ok.
For the relation between swg_sales_rep_user and s_user (OneToOne) I have problems. My first idea was extend the User model and add the additional logic we need. But this implies to overwrite my users table, take the risk to lose data.
What I did was create a SwgUser model that extends User model, like
SwgSalesRepresentativeUsers.php
/**
* #ORM\Entity
* #ORM\Table(name="swg_sales_rep_users")
*/
class SwgSalesRepresentativeUsers extends ModelEntity
{
...
/**
* #var \Shopware\CustomModels\SwagUserSalesRepresentative\SwgUser $user
*
* #ORM\OneToOne(targetEntity="Shopware\CustomModels\SwagUserSalesRepresentative\SwgUser", inversedBy="salesRepresentative")
* #ORM\JoinColumn(name="user_id", referencedColumnName="id")
*/
protected $user;
/**
* #return mixed
*/
public function getUser()
{
return $this->user;
}
/**
* #param $user
* #return ModelEntity
*/
public function setUser($user)
{
return $this->setOneToOne(
$user,
'\Shopware\CustomModels\SwagUserSalesRepresentative\SwgUser',
'user',
'salesRepresentative'
);
}
...
SwgUser.php
/**
* #ORM\Entity
* #ORM\Table(name="s_user")
*/
class SwgUser extends User
{
/**
*
* #ORM\OneToOne(targetEntity="Shopware\CustomModels\SwagUserSalesRepresentative\SwgSalesRepresentativeUsers", mappedBy="user")
*/
protected $salesRepresentative;
...
And bootstrap.php install/uninstall looks like
/**
* Install method
*
* #return bool
*/
public function install()
{
$this->updateSchema();
return true;
}
/**
* Uninstall method
*
* #return bool
*/
public function uninstall()
{
$this->registerCustomModels();
$em = $this->Application()->Models();
$tool = new \Doctrine\ORM\Tools\SchemaTool($em);
$classes = array(
$em->getClassMetadata('Shopware\CustomModels\SwagUserSalesRepresentative\SwgSalesRepresentative'),
$em->getClassMetadata('Shopware\CustomModels\SwagUserSalesRepresentative\SwgUser'),
$em->getClassMetadata('Shopware\CustomModels\SwagUserSalesRepresentative\SwgSalesRepresentativeUsers')
);
$tool->dropSchema($classes);
return true;
}
/**
* Creates the database scheme from existing doctrine models.
*
* Will remove the table first, so handle with care.
*/
protected function updateSchema()
{
$this->registerCustomModels();
$em = $this->Application()->Models();
$tool = new \Doctrine\ORM\Tools\SchemaTool($em);
$classes = array(
$em->getClassMetadata('Shopware\CustomModels\SwagUserSalesRepresentative\SwgSalesRepresentative'),
$em->getClassMetadata('Shopware\CustomModels\SwagUserSalesRepresentative\SwgUser'),
$em->getClassMetadata('Shopware\CustomModels\SwagUserSalesRepresentative\SwgSalesRepresentativeUsers')
);
try {
$tool->dropSchema($classes);
} catch (Exception $e) {
//ignore
}
$tool->createSchema($classes);
}
I tried to use the unidirectional association mapping and it creates the field but not the relation with s_user table (Foreign key).
So question is, how can I create relations with core tables on shopware without have to recreate (drop/create) the core tables?
Is it possible to alter tables programmatically? what is the best approach for these needs. Do you have an example that demonstrate this?
Thanks for helping.
there is no way to create bidirectional associations with shopware core tables yet. You can have unidirectional associations for sure, but you will not be able to add relational properties to core entities so far.
Except you intend to modify the shopware core itself which should be avoided at any time.
The only - and very tiny - possibility would be by trying to create a relation over a core entities attribute table which is quite "magic stuff" in shopware.
I'm try to serialize a MongoDB document with embedded documents within Symfony 2.1. I am using the JMSserializer and Mongodb-odm bundles.
I have the following Documents entities.
// Blog
namespace App\DocumentBundle\Document;
use Symfony\Component\Validator\Constraints as Assert;
use Doctrine\ODM\MongoDB\Mapping\Annotations as MongoDB;
use JMS\SerializerBundle\Annotation\Type;
/**
* #MongoDB\Document(repositoryClass="App\DocumentBundle\Repository\BlogRepository")
*/
class Blog {
/**
* #MongoDB\Id
*/
protected $id;
/**
* #MongoDB\String
* #Assert\NotBlank()
*/
protected $title;
/**
* #MongoDB\string
* #Assert\NotBlank()
*/
protected $blog;
/**
* #MongoDB\EmbedMany(targetDocument="Tag")
*/
private $tags;
/**
* #MongoDB\Timestamp
*/
protected $created;
/**
* #MongoDB\Timestamp
*/
protected $updated;
}
and
// Tag
namespace App\DocumentBundle\Document;
use Doctrine\ODM\MongoDB\Mapping\Annotations as MongoDB;
/**
* #MongoDB\EmbeddedDocument
*/
class Tag {
/**
* #MongoDB\String
*/
protected $name;
}
An ArrayCollection type is generated for the tag attribute, but the JMSSerializer bundle doesn't like it. If I change the tag to #MongoDB\String and regenerate the Blog document,
then serialization occurs, but not with #MongoDB\EmbedMany(targetDocument="Tag") set.
Do I need to specify some of the JMSSerializer annotated attributes allow embedded document to also be serialized?
You have to configure the expected type for JMSSerializer
Annotation :
/**
* #MongoDB\EmbedMany(targetDocument="Tag")
* #Type(ArrayCollection<App\DocumentBundle\Document\Tag>)
*/
private $tags;
Yaml :
tags:
expose: true
type: ArrayCollection<App\DocumentBundle\Document\Tag>
I have some problems with embedding document with Doctrine MongoDB ODM and Symfony 2.
To expose the problem, I have the document product embedOne productInformation, and productInformation embedOne productInformationAddress.
To query, I use something like that :
/**
* #ODM\Document
**/
class product {
/**
* #ODM\EmbedOne(targetDocument="productInformation")
**/
protected $informations;
}
/**
* #ODM\EmbeddedDocument
**/
class productInformations {
/**
* #ODM\EmbedOne(targetDocument="productInformationAddress")
**/
protected $address;
/**
* #ODM\Collection
**/
protected $attr1 = array();
/**
* #ODM\String
**/
protected $attr2
}
/**
* #ODM\EmbeddedDocument
**/
class productInformationAddress {
/** ... suff ... /*
}
When I query :
class productRepository {
public function fetchOne($id) {
return $this->createQueryBuilder()
->field('id')->equals($id)
->getQuery()
->getSingleResult();
}
}
But, I don't understand why I cannot get $product->getInformations()->getAddress(), that always return null...
Any idea?
I don't see a problem with the code you posted, but it would probably be helpful to read through ODM's functional tests for nested, embedded documents. In EmbeddedTest.php, the methods of interest would be anything that uses EmbeddedTestLevel2, which is equivalent to your productInformationAddress class, and testRemoveAddDeepEmbedded().