I'm using couchDb in symfony 2.7.2.
I have several doubts.
Now I installed this Bundle
And I create one entity for testing
<?php
namespace foo\GarageBundle\Document;
use Doctrine\ODM\CouchDB\Mapping\Annotations as CouchDB;
/**
* #CouchDB\Document
*/
class Utente
{
/** #CouchDB\Id */
private $id;
/** #CouchDB\Field(type="string") */
private $nome;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set nome
*
* #param string $nome
* #return Utente
*/
public function setNome($nome)
{
$this->nome = $nome;
return $this;
}
/**
* Get nome
*
* #return string
*/
public function getNome()
{
return $this->nome;
}
}
In my controller I added this Code
$dm = $this->container->get('doctrine_couchdb.client.default_connection');
$doc = $this->container->get('doctrine_couchdb.odm.default_document_manager');
try{
$dm->createDatabase($dm->getDatabase());
}catch(\Exception $e){
$msg = $e->getMessage();
}
$user = new Utente();
$user->setNome('foo');
$doc->persist($user);
$doc->flush();
my config.yml is
doctrine_couch_db:
client:
default_connection: default
connections:
default:
dbname: symfony2
odm:
default_document_manager: default
document_managers:
default:
auto_mapping: true
With controller I created Database but I can't insert the new Document, I got this error
The class 'foo\GarageBundle\Document\Utente' was not found in the chain configured namespaces
And I don't understand why it is useful to use a bundle as what I am using ( I know it could be a stupid question ), and why I have to use * #CouchDB\Document instead of #Document inside my entity ?
Seems a problem related the namespace of the entity class.
The automapping is registering the CouchDocument subnamespace of
your bundle, not Document (which is auto-mapped by
DoctrineMongoDBBundle)
So use a different namespace for the User class and the other Counch you use, as follow:
namespace foo\GarageBundle\CouchDocument;
In particular:
<?php
namespace foo\GarageBundle\CouchDocument;
use Doctrine\ODM\CouchDB\Mapping\Annotations as CouchDB;
/**
* #CouchDB\Document
*/
class Utente
{
Hope this help
See this discussion on github.
/**
* #CouchDB\Document
* #CouchDB\Index
*/
class Utente
{
Related
I am trying to build an entity object for my relationship in Neo4j database with GraphAware Neo4j PHP OGM library using this simple method:
public function getRelationshipEntity($entityId) {
$repo = $this->entityManager->getRepository( Entity\Relationship\Fired::class );
return $repo->findOneById($entityId);
}
Here we have the entity classes, relationship first:
namespace Entity\Relationship;
use GraphAware\Neo4j\OGM\Annotations as OGM;
use Entity\Issue;
use Entity\Event;
/**
* #OGM\RelationshipEntity(type="FIRED")
*/
class Fired {
/**
* #OGM\GraphId()
*/
protected $id;
/**
* #OGM\StartNode(targetEntity="Entity\Event")
*/
protected $event;
/**
* #OGM\EndNode(targetEntity="Entity\Issue")
*/
protected $issue;
/**
* #var string
*
* #OGM\Property(type="string")
*/
protected $time;
/**
* #var string
*
* #OGM\Property(type="string")
*/
protected $eventName;
}
Then, start node:
namespace Entity;
use GraphAware\Neo4j\OGM\Annotations as OGM;
/**
* #OGM\Node(label="Event")
*/
class Event {
/**
* #OGM\GraphId()
*/
protected $id;
/**
* #var string
*
* #OGM\Property(type="string")
*/
protected $name;
}
..and end node:
namespace Entity;
use Doctrine\Common\Collections\ArrayCollection;
use GraphAware\Neo4j\OGM\Annotations as OGM;
/**
* #OGM\Node(label="Issue")
*/
class Issue {
/**
* #OGM\GraphId()
*/
protected $id;
/**
* #OGM\Property(type="string")
*/
protected $key;
/**
* #OGM\Property(type="string")
*/
protected $created;
/**
* #OGM\Property(type="string")
*/
protected $updated;
/**
* #OGM\Relationship(type="FIRED", direction="INCOMING", relationshipEntity="Entity\Relationship\Fired", collection=true)
* #var ArrayCollection
*/
protected $eventFires;
public function __construct($key) {
$this->key = $key;
$this->eventFires = new ArrayCollection();
}
public function __wakeup() {
$this->__construct($this->key);
}
/**
* #return ArrayCollection
*/
public function getEventFires() {
return $this->eventFires;
}
public function addEventFire(Entity\Relationship\Fired $eventFired) {
$this->eventFires->add($eventFired);
}
public function removeEventFire(Entity\Relationship\Fired $eventFired) {
$this->eventFires->removeElement($eventFired);
}
}
Apparently, what works really well for node entites, triggers the following error for relationships:
Fatal error: Call to undefined method GraphAware\Neo4j\OGM\Metadata\RelationshipEntityMetadata::hasCustomRepository() in /vendor/graphaware/neo4j-php-ogm/src/EntityManager.php
Any suggestion how I could workaround this? I even tried using EntityManager::createQuery() the following way:
public function getRelationships($eventName) {
$query = $this->entityManager->createQuery('MATCH (e:Event)-[f:FIRED{eventName: {eventName}}]->() RETURN e,f ORDER BY f.time');
$query->addEntityMapping('e', 'Entity\Event' );
$query->addEntityMapping('f', 'Entity\Relationship\Fired' );
$query->setParameter( 'eventName', $eventName);
return $query->execute();
}
But, apparently, addEntityMapping() doesn't work for relationship entities either! (It might be a feature though, not a bug):
Catchable fatal error: Argument 1 passed to GraphAware\Neo4j\OGM\Hydrator\EntityHydrator::hydrateNode() must implement interface GraphAware\Common\Type\Node, instance of GraphAware\Bolt\Result\Type\Relationship given, called in /vendor/graphaware/neo4j-php-ogm/src/Query.php on line 145 and defined in /vendor/graphaware/neo4j-php-ogm/src/Hydrator/EntityHydrator.php on line 232
So, I ended up that I can easily define and store relationship entities in Neo4J with this library but not sure how I could retrieve it easily with EntityManager, in the similar way I can do so with nodes.
Any help would be much appreciated!
As requested in comment below, these are GraphAware packages that I am using:
graphaware/neo4j-bolt 1.9.1 Neo4j Bolt Binary Protocol PHP Driver
graphaware/neo4j-common 3.4.0 Common Utilities library for Neo4j
graphaware/neo4j-php-client 4.8.0 Neo4j-PHP-Client is the most advanced PHP Client for Neo4j
graphaware/neo4j-php-ogm 1.0.0-RC6 PHP Object Graph Mapper for Neo4j
I've created successfully a BE user in an own extension for TYPO3 CMS 8.7.0.
Repository Injection:
/**
* beUserRepository
*
* #var \TYPO3\CMS\Extbase\Domain\Repository\BackendUserRepository
* #inject
*/
protected $beUserRepository = null;
Part of the ActionController:
$beuser = new \TYPO3\CMS\Extbase\Domain\Model\BackendUser();
$beuser->setUserName($username);
$beuser->setEmail($email);
$beuser->setRealName($realname);
$this->beUserRepository->add($beuser);
This works fine but I can't add a password like for FE users with setPassword(). Is there any way to get there or is it restricted for security reasons to set/change a BE user password?
Create your own BackendUser model in your extension
<?php
namespace YourVendor\YourExtKey\Domain\Model;
class BackendUser extends \TYPO3\CMS\Extbase\Domain\Model\BackendUser
{
/**
* #var string
*/
protected $password = '';
/**
* Returns the password
*
* #return string
*/
public function getPassword()
{
return $this->password;
}
/**
* Sets the password
*
* #param string $password
* #return void
*/
public function setPassword($password)
{
$this->password = (string)$password;
}
}
Create your own Repository
<?php
namespace YourVendor\YourExtKey\Domain\Repository;
class BackendUserRepository extends \TYPO3\CMS\Extbase\Domain\Repository\BackendUserRepository
{
}
Then map your new domain model to be_users table:
plugin.tx_yourExtKey {
persistence {
classes {
YourVendor\YourExtKey\Domain\Model\BackendUser {
mapping {
tableName = be_users
}
}
}
}
}
Update your controller to use your new Repository
/**
* beUserRepository
*
* #var \YourVendor\YourExtKey\Domain\Repository\BackendUserRepository
* #inject
*/
protected $beUserRepository;
Back in your action
$beUser = new \YourVendor\YourExtKey\Domain\Model\BackendUser();
$saltFactory = \TYPO3\CMS\Saltedpasswords\Salt\SaltFactory::getSaltingInstance('', 'BE');
$beUser->setPassword($saltFactory->getHashedPassword($newPassword));
TYPO3\CMS\Extbase\Domain\Model\BackendUser does not have a password property, so you can not set a password without extending the model. The easiest way would be if you create an own BackendUser model in your extension that extends the TYPO3\CMS\Extbase\Domain\Model\BackendUser and configure the mapping in TS. It just needs to have the $password property with getters/setters and a repository.
I have several classes using a Taggable trait to set up a tag system common to several doctrine entities (Project, Note, ...).
The relationship between these entities and these tags is a ManyToMany relationship that I can not make multi-directional.
My problem: When I delete a Project entity, it is removed from the project table, but the relationships in the project_tag table between this project and the tags are not deleted. Then, if I create a new Project entity, an exception is thrown.
An exception exists while executing 'INSERT INTO project_tag (project_id, tag_id) VALUES (?,?)' With params [2, 4]:
SQLSTATE [23000]: Integrity constraint violation: 19 UNIQUE constraint failed: project_tag.project_id, project_tag.tag_id
Entities :
Tag
/**
* Tag
*
* #ORM\Table(name="tag")
* #ORM\Entity(repositoryClass="AppBundle\Repository\TagRepository")
*/
class Tag
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="name", type="string", length=255, unique=true)
*/
private $name;
/**
* #ORM\Column(name="last_use_at", type="datetime", nullable=false)
* #var \DateTime
*/
private $lastUseAt;
public function __construct()
{
$this->lastUseAt = new \DateTime();
}
public function __toString()
{
return $this->name;
}
/**
* Get id
*
* #return int
*/
public function getId()
{
return $this->id;
}
/**
* Set name
*
* #param string $name
*
* #return Tag
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* #return string
*/
public function getName(): string
{
return $this->name;
}
/**
* #return \DateTime
*/
public function getLastUseAt(): \DateTime
{
return $this->lastUseAt;
}
/**
* #param \DateTime $lastUseAt
*/
public function setLastUseAt(\DateTime $lastUseAt)
{
$this->lastUseAt = $lastUseAt;
}
}
Taggable
trait Taggable
{
/**
* #var ArrayCollection
*
* #ORM\ManyToMany(targetEntity="AppBundle\Entity\Tag", cascade={"persist"})
*/
protected $tags;
/**
* Add tag
*
* #param Tag $tag
*
* #return $this
*/
public function addTag(Tag $tag)
{
$tag->setLastUseAt(new \DateTime());
$this->tags[] = $tag;
return $this;
}
/**
* Remove tag
*
* #param Tag $tag
*/
public function removeTag(Tag $tag)
{
$this->tags->removeElement($tag);
}
/**
* Get tags
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getTags()
{
return $this->tags;
}
}
Project
/**
* Project
*
* #ORM\Table(name="project")
* #ORM\Entity(repositoryClass="AppBundle\Repository\ProjectRepository")
*/
class Project
{
use Taggable;
}
Note
class Note
{
use Taggable;
}
Is this the only solution or is my annotation incomplete / incorrect?
I tried with JoinColumns, JoinTable and onDelete = "cascade" but nothing works.
In the meantime, I dodged the problem with this instruction placed before the suppresion.
$project->getTags()->clear();
Full code of the action in the controller :
/**
* #Route("/project/{id}/delete", name="project_delete")
*/
public function deleteAction($id) {
$em = $this->getDoctrine()->getManager();
$project = $em->getRepository('AppBundle:Project')->find($id);
if(!$project) {
return $this->redirectToRoute('index');
}
$project->getTags()->clear();
$em->remove($project);
$em->flush();
return $this->redirectToRoute('index');
}
I think I found a better solution: you can set the PRAGMA within Doctrine configuration. Like:
doctrine:
dbal:
# configure these for your database server
driver: 'pdo_sqlite'
#server_version: '5.7'
#charset: utf8mb4
#default_table_options:
#charset: utf8mb4
#collate: utf8mb4_unicode_ci
url: '%env(resolve:DATABASE_URL)%'
options:
'PRAGMA foreign_keys': 'ON'
I just tried it on my Symfony 4 application, re-created the database and tested using DB Browser for SQLite and it works as I expected.
Hope this helps
I managed to fix the problem. Here's my solution working for SQLite conections.
Create an eventListener listening on the kernel.request event :
namespace AppBundle\EventListener;
use Doctrine\Bundle\DoctrineBundle\Registry;
use Doctrine\Common\Persistence\ObjectManager;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
class RequestListener
{
/**
* #var Registry
*/
private $doctrine;
public function __construct(Registry $doctrine)
{
$this->doctrine = $doctrine;
}
public function onKernelRequest(GetResponseEvent $event)
{
$this->doctrine->getConnection()->exec('PRAGMA foreign_keys = ON');
}
}
Service declaration
app.event_listener.request_listener:
class: AppBundle\EventListener\RequestListener
arguments:
- '#doctrine'
tags:
- { name: kernel.event_listener, event: kernel.request }
I think the problem is that you have your trait Taggable set as the owning side of the ManyToMany relationship but your are deleting the inverse side and expecting something to happen as a result. Doctrine will only check the owning side of the relationship in order to persist any changes. See here for docs on this.
You can solve by making the Taggable the inverse side of each of your relationships, or by manually telling doctrine to delete the owning side.
The first solution will probably not work for you since you won't (easily) specify multiple inverse sides. (Are you sure a trait is the right way to go for this??)
The second solution is easy. In your entities like Project for your deleteTag($tag) function, call a delete function on the owning side (e.g., deleteProject($project). You will have to create if one does not exist.
class Project
{
use Taggable;
public function deleteTag($tag)
{
$this->tags->removeElement($tag);
// persist on the owning side
$tag->deleteProject($this);
}
}
EDIT:
After seeing full code, it looks like you are deleting correctly. Now you need to tell doctrine to carry that through. See this post for full details, but basically you can change your trait to this:
trait Taggable
{
/**
* #var ArrayCollection
*
* #ORM\ManyToMany(
* targetEntity="AppBundle\Entity\Tag",
* cascade={"persist"},
* onDelete="CASCADE"
* )
*/
protected $tags;
// ...
}
Before starting, the usual disclaimer : I am aware of dozens of questions here on SE from people encountering identical-looking problems, I have browsed them and unless I missed something, the combination of all the fixes proposed does not solve my particular problem.
In particular :
This question is about duplicated
and inherited entities, which I don't have.
This answer is about
invalid annotation format (missing asterisks), which I don't have in my entity definition (see file content below).
In this question, the problem
comes from a #todo somewhere, which I don't use
In this question, the problem
comes from using eAccelerator which I'm not using at this point
I get the following error message in Symfony :
Doctrine\ORM\Mapping\MappingException: Class "AppBundle\Entity\User" is not a valid entity or mapped super class.
Yet, other commands tell me everything is fine :
$ php bin/console doctrine:mapping:info
Found 6 mapped entities:
[OK] AppBundle\Entity\Category
[OK] AppBundle\Entity\Comment
[OK] AppBundle\Entity\Post
[OK] AppBundle\Entity\Section
[OK] AppBundle\Entity\User
[OK] AppBundle\Entity\World
I also tried
try {
$entityManager->getConnection()->connect();
} catch (\Exception $e) {
echo 'Connection failed !';
}
in my code to see if the connection worked. I also tried "registering noop annotation autoloader" as
suggested in this SO answer
the content of my test file below reflects this ;
<?php
error_reporting(E_ALL|E_STRICT);
require 'app/autoload.php';
xdebug_break();
use AppBundle\Entity;
use Doctrine\ORM\Tools\Setup;
use Doctrine\ORM\EntityManager;
use Doctrine\ORM\Mapping\Driver\AnnotationDriver;
use Doctrine\Common\Annotations\AnnotationReader;
use Doctrine\Common\Annotations\AnnotationRegistry;
$paths = array("src/AppBundle/Entity");
$isDevMode = true;
// the connection configuration
$dbParams = array(
'driver' => 'pdo_mysql',
'user' => 'root',
'password' => 'root',
'dbname' => 'asharis_database'
);
$config = Setup::createAnnotationMetadataConfiguration($paths, $isDevMode);
$driver = new AnnotationDriver(new AnnotationReader(), $paths);
// registering noop annotation autoloader - allow all annotations by default
AnnotationRegistry::registerLoader('class_exists');
$config->setMetadataDriverImpl($driver);
$entityManager = EntityManager::create($dbParams, $config);
try {
$entityManager->getConnection()->connect();
} catch (\Exception $e) {
echo 'Connection failed !';
}
$users=array();
$post=array();
for($u=1;$u<=3;$u++) {
$user=new AppBundle\Entity\User();
$users[]=$user;
try {
$entityManager->persist($user);
} catch (\Exception $e) {
var_dump($e);
}
And here is the content of User.php :
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validation\Constraints as Assert;
/**
* #ORM\Entity
* #ORM\Table(name="user")
*
**/
class User
{
/**
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
* #ORM\Column(type="integer")
*/
private $id;
/**
* #ORM\OneToMany(
* targetEntity="Comment",
* mappedBy="post",
* orphanRemoval=true
* )
*
*/
private $comments;
/**
* #ORM\OneToMany(
* targetEntity="Post",
* mappedBy="post",
* orphanRemoval=true
* )
*
*/
private $posts;
/**
* Constructor
*/
public function __construct()
{
$this->comments = new \Doctrine\Common\Collections\ArrayCollection();
$this->posts = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Add comment
*
* #param \AppBundle\Entity\Comment $comment
*
* #return User
*/
public function addComment(\AppBundle\Entity\Comment $comment)
{
$this->comments[] = $comment;
return $this;
}
/**
* Remove comment
*
* #param \AppBundle\Entity\Comment $comment
*/
public function removeComment(\AppBundle\Entity\Comment $comment)
{
$this->comments->removeElement($comment);
}
/**
* Get comments
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getComments()
{
return $this->comments;
}
/**
* Add post
*
* #param \AppBundle\Entity\Posts $post
*
* #return User
*/
public function addPost(\AppBundle\Entity\Posts $post)
{
$this->posts[] = $post;
return $this;
}
/**
* Remove post
*
* #param \AppBundle\Entity\Posts $post
*/
public function removePost(\AppBundle\Entity\Posts $post)
{
$this->posts->removeElement($post);
}
/**
* Get posts
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getPosts()
{
return $this->posts;
}
}
Any help appreciated.
"user" is a reserved key word in most database systems.
But that's why you don't see issues when validating your scheme but get issues later on.
I personally had the case that I was able to even create my schema, but when I used DQL I got some issues.
So you have to avoid or handle the "reserved key word". You have two options:
1)
Rename your class or at least give it a different database table name by:
/**
* #ORM\Entity
* #ORM\Table(name="myapp_user")
*
**/
2)
You could also use Doctrine's way to handle reserved keywords (see documentation):
/**
* #ORM\Entity
* #ORM\Table(name="'user'")
*
**/
But I personally don't recommend the second option.
See as well this section about known limitations in Doctrine around your issue here
Small note: I am assuming that you aren't using the FOS User Bundle - in that case your user would need to extend the BaseUser class additionally.
I am working on an authentication with FpOpenIdBundle but i get this error
Catchable Fatal Error: Argument 1 passed to Fp\OpenIdBundle\Model\UserIdentity::setUser() must implement interface Symfony\Component\Security\Core\User\UserInterface, instance of Doctrine\ODM\MongoDB\DocumentRepository given, called in C:\xampp\htdocs\project\src\AppBundle\Security\User\OpenIdUserManager.php on line 64 and defined
I followed the doc (https://github.com/formapro/FpOpenIdBundle/blob/master/Resources/doc/configure_user_manager.md)
I have made a manager
namespace AppBundle\Security\User;
use AppBundle\Document\User;
use AppBundle\Document\OpenIdIdentity;
use Doctrine\ODM\MongoDB\DocumentManager;
use Fp\OpenIdBundle\Model\UserManager;
use Fp\OpenIdBundle\Model\IdentityManagerInterface;
class OpenIdUserManager extends UserManager
{
/**
* #var DocumentManager
*/
private $documentManager;
/**
* OpenIdUserManager constructor.
*
* #param IdentityManagerInterface $identityManager
* #param DocumentManager $documentManager
*/
public function __construct(IdentityManagerInterface $identityManager, DocumentManager $documentManager)
{
parent::__construct($identityManager);
$this->documentManager = $documentManager;
}
/**
* #param string $identity
* #param array $attributes
*
* #return \Doctrine\ODM\MongoDB\DocumentRepository
*/
public function createUserFromIdentity($identity, array $attributes = array())
{
$user = $this->documentManager->getRepository('AppBundle:User');
$openIdIdentity = new OpenIdIdentity();
$openIdIdentity->setIdentity($identity);
$openIdIdentity->setAttributes($attributes);
$openIdIdentity->setUser($user);
$this->documentManager->persist($openIdIdentity);
$this->documentManager->flush();
return $user;
}
}
The error is returned because of this line
$openIdIdentity->setUser($user);
I use this manager as the service like this
services:
fp_openid.manager:
class: AppBundle\Security\User\OpenIdUserManager
arguments: [ '#fp_openid.identity_manager', '#doctrine.odm.mongodb.document_manager' ]
Who's called by my security.yml
security:
firewalls:
main:
fp_openid:
create_user_if_not_exists: true
provider: openid_user_manager
providers:
openid_user_manager:
id: fp_openid.manager
main:
entity:
{ class: AppBundle:User, property: personaName }
I finally made a MongoDB document as they said
namespace AppBundle\Document;
use Doctrine\ODM\MongoDB\Mapping\Annotations as MongoDB;
use Symfony\Component\Security\Core\User\UserInterface;
use Fp\OpenIdBundle\Document\UserIdentity as BaseUserIdentity;
/**
* #MongoDB\Document(collection="openid_identities")
*/
class OpenIdIdentity extends BaseUserIdentity
{
/**
* #MongoDB\Id(strategy="auto")
*/
protected $id;
/**
* {#inheritdoc}
* #MongoDB\String
*/
protected $identity;
/**
* {#inheritdoc}
* #MongoDB\Hash
*/
protected $attributes;
/**
* #var UserInterface
*
* #MongoDB\ReferenceOne(targetDocument="AppBundle\Document\User", simple=true)
*/
protected $user;
public function __construct()
{
parent::__construct();
}
}
Everythings is working well except this problem, i don't understand why this is not working whereas i do the same as the doc said. I must implement UserInterface instead of instance of DocumentRepository but they use their user document instead.
Does some already use this bundle and had this issue ?
Thanks for helping
Please carefully read the doc again, in the doc it's:
$user = $this->entityManager->getRepository('AcmeDemoBundle:User')->findOneBy(array(
'email' => $attributes['contact/email']
));