After doctrine createQueryBuilder execute, I get results with a property of objects that is not filled.
here my code
In UserSecurityManager (service)
... $repository = $this->em->getRepository('VenusUserBundle:Role');
$query = $repository->createQueryBuilder('r')
->where('r.lft >= :role_lft AND r.rgt <= :role_rgt')
->orderBy('r.rgt', 'ASC')
->setParameter('role_lft', $result['lft'])
->setParameter('role_rgt', $result['rgt'])
->getQuery();
$availableRoles = $query->getResult(); ...
//debug
foreach ($availableRoles as $key => $value) { echo '<br>CODE='.$value->getCode().' LFT='.$value->getLft().' NAME=('.$value->getName().') * '; }
...
Role Class
namespace MyApp\UserBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Security\Core\Role\RoleInterface;
/**
* #ORM\Entity
* #ORM\Table(name="Role")
*/
class Role implements RoleInterface, \Serializable
{
/**
* #ORM\Id
* #ORM\Column(type="string", length=100)
*
* #var string $code
*/
protected $code;
/**
* #ORM\Column(name="name", type="string", length=100)
*
* #var string $name
*/
private $name;
/**
* #ORM\Column(type="integer")
*
* #var integer $lft
*/
protected $lft; //nested tree
/**
* #ORM\Column(type="integer")
*
* #var integer $rgt
*/
protected $rgt; //nested tree
/**
* #ORM\OneToMany(targetEntity="Role", mappedBy="parent")
*/
private $children;
/**
* #ORM\ManyToOne(targetEntity="Role", inversedBy="children")
* #ORM\JoinColumn(name="parent_code", referencedColumnName="code")
*/
private $parent;
/**
* #ORM\ManyToMany(targetEntity="User", mappedBy="roles")
*
* #var \Doctrine\Common\Collections\ArrayCollection
*/
protected $users;
public function __construct()
{
$this->name = '';
$this->users = new \Doctrine\Common\Collections\ArrayCollection();
$this->children = new \Doctrine\Common\Collections\ArrayCollection();
}
// #see \Serializable::serialize()
public function serialize()
{
// ! Don't serialize $users field !
return \serialize(array(
$this->code,
$this->name,
$this->parent,
$this->children,
));
}
// #see \Serializable::unserialize()
public function unserialize($serialized)
{
list(
$this->code,
$this->name,
$this->parent,
$this->children,
) = \unserialize($serialized);
}
//public function __toString() {
// return $this->name;
//}
/**
* Sets the role code.
*
* #param string $value The code.
*/
public function setCode($value)
{
$this->code = $value;
}
/**
* Gets the code.
*
* #return integer The code.
*/
public function getCode()
{
return $this->code;
}
/**
* Gets the role name.
*
* #return string The name.
*/
public function getName()
{
return $this->name;
}
/**
* Sets the role name.
*
* #param string $name The name.
*/
public function setName($name)
{
$this->name = $name;
}
/**
* Get parent
*
* #return MyApp\UserBundle\Entity\Role
*/
public function getParent()
{
return $this->parent;
}
/**
* Set parent
*
* #param MyApp\UserBundle\Entity\Role $role
*/
public function setParent(\MyApp\UserBundle\Entity\Role $role)
{
$this->parent = $role;
}
/**
* Gets the role left.
*
* #return string The left.
*/
public function getLft()
{
return $this->lft;
}
/**
* Sets the role left.
*
* #param string $left Left.
*/
public function setLft($lft)
{
$this->lft = $lft;
}
public function getRole()
{
return $this->code;
}
/**
* Remove a user
*
* #param \MyApp\UserBundle\Entity\User $user
*/
public function removeUser(\MyApp\UserBundle\Entity\User $user)
{
$this->users->removeElement($user);
}
/**
* Add a user
*
* #param \MyApp\UserBundle\Entity\User $user
*/
public function addUser(\MyApp\UserBundle\Entity\User $user)
{
$this->users->add($user);
}
/**
* Remove all users
*
*/
public function removeUsers()
{
$this->users->clear();
}
/**
* Set the collection of related users
*
* #param \Doctrine\Common\Collections\ArrayCollection $users
*/
public function setUsers(\Doctrine\Common\Collections\ArrayCollection $users)
{
$this->users = $users;
}
/**
* Get users
*
* #return Doctrine\Common\Collections\Collection
*/
public function getUsers()
{
return $this->users;
}
}
The line
foreach ($availableRoles as $key => $value) {
echo '<br>CODE='.$value->getCode().' LFT='.$value->getLft().' NAME=('.$value->getName().') * '; }
Display
CODE=client LFT=4 NAME=(client) *
CODE=studio LFT=6 NAME=(studio) *
CODE=commercial LFT=8 NAME=(commercial) *
CODE=user_manager LFT=11 NAME=(user manager) *
CODE=company_manager LFT=13 NAME=(company manager) *
CODE=admin LFT=3 NAME=(administrator) *
CODE=prod LFT=10 NAME=(prod) *
CODE=superadmin LFT= NAME=() * //<-- THE BUG : name is empty !!!
CODE=root LFT=1 NAME=(megaroot) *
And the data in database :
code parent_code name lft rgt
admin superadmin administrator 3 15
client admin client 4 5
commercial admin commercial 8 9
company_manager admin company manager 13 14
prod admin prod 10 15
root NULL megaroot 1 18
studio admin studio 6 7
superadmin root superadmin 2 15
user_manager admin user manager 11 12
for superadmin, The property "name" is not filled, I don't understand.
Do you have an idea ?
I made some other tests :
If the parent of role "administrator" is the role "client"
code parent_code name lft rgt
admin client administrator 3 15
client admin client 4 5
commercial admin commercial 8 9
company_manager admin company manager 13 14
prod admin prod 10 15
root NULL megaroot 1 18
studio admin studio 6 7
superadmin root superadmin 2 15
user_manager admin user manager 11 12
CODE=client LFT= NAME=() * <-- BUG HERE !!!
CODE=studio LFT=6 NAME=(studio) *
CODE=commercial LFT=8 NAME=(commercial) *
CODE=user_manager LFT=11 NAME=(user manager) *
CODE=company_manager LFT=13 NAME=(company manager) *
CODE=admin LFT=3 NAME=(administrator) *
CODE=prod LFT=10 NAME=(prod) *
CODE=superadmin LFT=2 NAME=(superadmin) *
CODE=root LFT=1 NAME=(megaroot) *
If the parent of role "administrator" is the role "client" and the parent of role "client" is the role "root"
code parent_code name lft rgt
admin client administrator 3 15
client admin client 4 5
commercial admin commercial 8 9
company_manager admin company manager 13 14
prod admin prod 10 15
root NULL megaroot 1 18
studio admin studio 6 7
superadmin root superadmin 2 15
user_manager admin user manager 11 12
CODE=client LFT= NAME=() * <-- BUG HERE !!!
CODE=studio LFT=6 NAME=(studio) *
CODE=commercial LFT=8 NAME=(commercial) *
CODE=user_manager LFT=11 NAME=(user manager) *
CODE=company_manager LFT=13 NAME=(company manager) *
CODE=admin LFT=3 NAME=(administrator) *
CODE=prod LFT=10 NAME=(prod) *
CODE=superadmin LFT=2 NAME=(superadmin) *
CODE=root LFT= NAME=() * <-- BUG HERE !!!
Thanks and sorry for my english.
Phil
If I execute
$query->setHint(\Doctrine\ORM\Query::HINT_REFRESH, true);
before
$availableRoles = $query->getResult();
ok, the result is good but I don't know the cause yet :s.
The problem come from my code ?! or it's a bug in doctrine 2.4 ?
it would be a problem with doctrine cache.
When I call this "entitymanager->clear()" before execute query, all is good.
$this->em->clear('MyApp\UserBundle\Entity\Role');
$repository = $this->em->getRepository('MyAppUserBundle:Role');
What's the explain of this problem of cache ? Because I don't configure caching in my symfony project.
is "em->clear()" dangerous for the rest of application ?
Related
Symfony 2.8. When using default fetch mode duplicates are returned (why?), using fetch="EAGER" - everything is ok.
I have following objects:
/**
* #ORM\Entity()
*/
class User implements AdvancedUserInterface, \Serializable
{
(...)
/**
* #ORM\ManyToMany(targetEntity="Role", inversedBy="users")
* #ORM\JoinTable(name="user_role",
* joinColumns={#ORM\JoinColumn(name="user_id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="role_id", referencedColumnName="id")}
* )
*/
private $role;
public function addRole(\WerbeoBundle\Entity\Role $role)
{
$this->role[] = $role;
return $this;
}
public function removeRole(\WerbeoBundle\Entity\Role $role)
{
$this->role->removeElement($role);
}
public function getRole()
{
return $this->role;
}
Role:
/**
* #ORM\Entity()
*/
class Role
{
(...)
/**
* #ORM\ManyToMany(targetEntity="User", mappedBy="role")
*/
private $users;
(... and getters/setters ...)
Now I have following table user_role:
user_id | role_id
1 | ADMIN
1 | EDITOR
When I call $user->getRole() result is
ADMIN
EDITOR
EDITOR
ADMIN
EDITOR
This happens in twig/controller only when using default fetch mode (lazy). When fetch="EAGER" everything is ok.
Any ideas what am I doing wrong?
Thanks
You have to check if an entry already exists before adding
public function __construct()
{
$this-role = new \Doctrine\Common\Collections\ArrayCollection()
}
public function addRole(\WerbeoBundle\Entity\Role $role)
{
if(!$this->role->contains($role)){
$this->role->add($role)
}
return $this;
}
I want to be able to select a school (that has its own entity) while creating a mission (also has its entity)
Since a school can have several missions, and you can select several schools at the mission's creation, I used a ManyToMany.
The problem is that after creating this "ManyToMany", generating the entities and updating my schema, Symfony created a table, but left it totally empty, without the two columns that I asked for. I'm not really used to Symfony nor to the ManyToMany system, so I might have done some mistake without noticing it, still I find this weird.
Here's the interesting part of my ecole (school) entity:
class Ecole{
// ...
/**
* #ORM\ManyToMany(targetEntity="MissionBundle\Entity\Mission", mappedBy="ecolesDispo")
*/
protected $missionsDispos;
// ...
/**
* Add missionsDispo
*
* #param \MissionBundle\Entity\Mission $missionsDispo
*
* #return Ecole
*/
public function addMissionsDispo(\MissionBundle\Entity\Mission $missionsDispo)
{
$this->missionsDispos[] = $missionsDispo;
return $this;
}
/**
* Remove missionsDispo
*
* #param \MissionBundle\Entity\Mission $missionsDispo
*/
public function removeMissionsDispo(\MissionBundle\Entity\Mission $missionsDispo)
{
$this->missionsDispos->removeElement($missionsDispo);
}
/**
* Get missionsDispos
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getMissionsDispos()
{
return $this->missionsDispos;
}
And here is the interesting part of my mission entity:
/**
* #ORM\ManyToMany(targetEntity="EcoleBundle\Entity\Ecole", inversedBy="missionsDispo")
* #ORM\JoinTable(name="Mission2Ecole",
* joinColumns={#ORM\JoinColumn(name="em_id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="me_id", referencedColumnName="id")}
* )
*/
protected $ecolesDispo;
// ...
/**
* Constructor
*/
public function __construct()
{
$this->ecolesDispo = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* Add ecolesDispo
*
* #param \EcoleBundle\Entity\Ecole $ecolesDispo
*
* #return Mission
*/
public function addEcolesDispo(\EcoleBundle\Entity\Ecole $ecolesDispo)
{
$this->ecolesDispo[] = $ecolesDispo;
return $this;
}
/**
* Remove ecolesDispo
*
* #param \EcoleBundle\Entity\Ecole $ecolesDispo
*/
public function removeEcolesDispo(\EcoleBundle\Entity\Ecole $ecolesDispo)
{
$this->ecolesDispo->removeElement($ecolesDispo);
}
/**
* Get ecolesDispo
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getEcolesDispo()
{
return $this->ecolesDispo;
}
After all this was created, I was supposed to get a multi selector with the list of all the schools saved in the database (I already added it to the missionType file), but I get absolutely nothing.
I don't really know if I inverted the annotations, or if the "joinTable" part is correct, but I'm completely lost here.
Does anyone have an idea?
Thank you in advance
Just wrong typo "s"? inversedBy="missionsDispo" >>> inversedBy="missionsDispos"
PS. Official doc here
http://doctrine-orm.readthedocs.io/projects/doctrine-orm/en/latest/reference/association-mapping.html#many-to-many-bidirectional
I have this two tables (see pics below) mapped as follow:
class Brand
{
...
/**
* #var Company
*
* #ORM\ManyToOne(targetEntity="Company")
* #ORM\JoinColumn(name="companies_id", referencedColumnName="id")
*/
protected $company;
}
class Company
{
...
}
I need to add support for add a new Brand from Company but I have not idea in how to achieve this. This are handled through SonataAdminBundle but I think I need to add something else to entities in order to create brands from company but I am not sure what this would be, can I get some help? I am stucked
1st attempt
After get an answer this is how I modify Company entity:
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
class Company
{
...
/**
* #var Brand
* #ORM\OneToMany(targetEntity="Brand", mappedBy="company", cascade={"persist"})
**/
protected $brands;
public function __construct()
{
$this->brands = new ArrayCollection();
}
...
public function getBrands()
{
return $this->brands;
}
/**
* Add brands
*
* #param Brand $brand
* #return Brands
*/
public function addBrand( Brand $brand)
{
$this->brands[] = $brand;
return $this;
}
/**
* Remove brands
*
* #param Brand $brand
*/
public function removeBrand( Brand $brand)
{
$this->brands->removeElement($brand);
}
}
But I am getting this error:
No entity manager defined for class
Doctrine\Common\Collections\ArrayCollection
Why is that?
You could try setting up your entities like this:
class Brand
{
/**
* #var Company
*
* #ORM\ManyToOne(targetEntity="Company", inversedBy="brands")
* #ORM\JoinColumn(name="companies_id", referencedColumnName="id")
*/
protected $company;
}
class Company
{
/**
* #var ArrayCollection
*
* #OneToMany(targetEntity="Brand", mappedBy="company", cascade={"persist"})
**/
protected $brands;
}
What we're defining here is that new Brands can be created from the Company entity with cascade={"persist"}.
It's recommended you implement addBrand and removeBrand in Company for direct interaction with the ArrayCollection.
A simple example of the final functionality:
$company = $service->getCompany(1); // our company entity
$brand = new Brand();
$brand->set...
...
$company->addBrand($brand);
$entityManager->persist($company);
EDIT
This is just an example, you may choose not to add with keys or even implement a remove function, but this is a starting point:
public function addBrand(Brand $brand)
{
// key needs to be something that can uniquely identify the brand
// e.g. name
$this->getBrands()->set(*key*, $brand);
return $this;
}
public function removeBrand($key)
{
$this->getBrands()->remove($key);
return $this;
}
I am working with Symfony 2.6 and trying to setup PayumBundle (paypal express checkout) and I am getting an error
InvalidConfigurationException in BaseNode.php line 313: Invalid configuration for path "payum.security.token_storage": The storage entry must be a valid model class. It is set Acme\featuresBundle\Entity\PaymentToken
I am following the steps mentioned in there documetation
This is how my config.yml looks like
doctrine:
orm:
auto_generate_proxy_classes: "%kernel.debug%"
entity_managers:
default:
auto_mapping: true
mappings:
payum:
is_bundle: false
type: xml
dir: %kernel.root_dir%/../vendor/payum/core/Payum/Core/Bridge/Doctrine/Resources/mapping
prefix: Payum\Core\Model
payum:
security:
token_storage:
Acme\featuresBundle\Entity\PaymentToken: { doctrine: orm }
storages:
Acme\featuresBundle\Entity\PaymentDetails: { doctrine: orm }
contexts:
paypal:
paypal_express_checkout_nvp:
username: 'asdasd'
password: 'adsasd'
signature: 'asdasdasd'
sandbox: true
This is my Entity PaymentToken
namespace Acme\featuresBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Payum\Core\Model\Token;
/**
* #ORM\Table
* #ORM\Entity
*/
class PaymentToken extends Token
{
}
And this is Entity PaymentDetails
namespace Acme\featuresBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Payum\Core\Model\Order as BaseOrder;
/**
* #ORM\Table
* #ORM\Entity
*/
class PaymentDetails extends BaseOrder
{
/**
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*
* #var integer $id
*/
protected $id;
}
I have gone through alot of documentation online and other posts like this but I dont understand why I am getting this error.
The storage entry must be a valid model class. It is set Acme\featuresBundle\Entity\PaymentToken
I cant even get to the controller so something tells me it is the config.yml configuration of Payum that is not set correctly. I have gone through the documentation over and over and over and I cant seem to find what am I doing wrong.
I will really appreciate any help in getting pass this error.
I finally managed to get it done.
I needed 4 files
PaymentController
Orders (Entity)
PaymentToken (Entity)
Orders (Model)
This is my PaymentController looks like
<?php
namespace ClickTeck\featuresBundle\Controller;
use ClickTeck\featuresBundle\Entity\Orders;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Payum\Paypal\ExpressCheckout\Nvp\Api;
use Payum\Core\Registry\RegistryInterface;
use Payum\Core\Request\GetHumanStatus;
use Payum\Core\Security\GenericTokenFactoryInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\JsonResponse;
use Sensio\Bundle\FrameworkExtraBundle\Configuration as Extra;
class PaymentController extends Controller
{
public function preparePaypalExpressCheckoutPaymentAction(Request $request)
{
$paymentName = 'paypal';
$eBook = array(
'author' => 'Jules Verne',
'name' => 'The Mysterious Island',
'description' => 'The Mysterious Island is a novel by Jules Verne, published in 1874.',
'price' => 8.64,
'currency_symbol' => '$',
'currency' => 'USD',
'clientId' => '222',
'clientemail' => 'xyz#abc.com'
);
$storage = $this->get('payum')->getStorage('ClickTeck\featuresBundle\Entity\Orders');
/** #var $paymentDetails Orders */
$paymentDetails = $storage->create();
$paymentDetails->setNumber(uniqid());
$paymentDetails->setCurrencyCode($eBook['currency']);
$paymentDetails->setTotalAmount($eBook['price']);
$paymentDetails->setDescription($eBook['description']);
$paymentDetails->setClientId($eBook['clientId']);
$paymentDetails->setClientEmail($eBook['clientemail']);
$paymentDetails['PAYMENTREQUEST_0_CURRENCYCODE'] = $eBook['currency'];
$paymentDetails['PAYMENTREQUEST_0_AMT'] = $eBook['price'];
$paymentDetails['NOSHIPPING'] = Api::NOSHIPPING_NOT_DISPLAY_ADDRESS;
$paymentDetails['REQCONFIRMSHIPPING'] = Api::REQCONFIRMSHIPPING_NOT_REQUIRED;
$paymentDetails['L_PAYMENTREQUEST_0_ITEMCATEGORY0'] = Api::PAYMENTREQUEST_ITERMCATEGORY_DIGITAL;
$paymentDetails['L_PAYMENTREQUEST_0_AMT0'] = $eBook['price'];
$paymentDetails['L_PAYMENTREQUEST_0_NAME0'] = $eBook['author'].'. '.$eBook['name'];
$paymentDetails['L_PAYMENTREQUEST_0_DESC0'] = $eBook['description'];
$storage->update($paymentDetails);
$captureToken = $this->getTokenFactory()->createCaptureToken(
$paymentName,
$paymentDetails,
'payment_done'
);
$paymentDetails['INVNUM'] = $paymentDetails->getId();
$storage->update($paymentDetails);
return $this->redirect($captureToken->getTargetUrl());
}
public function doneAction(Request $request)
{
$token = $this->get('payum.security.http_request_verifier')->verify($request);
$payment = $this->get('payum')->getPayment($token->getPaymentName());
// you can invalidate the token. The url could not be requested any more.
// $this->get('payum.security.http_request_verifier')->invalidate($token);
// Once you have token you can get the model from the storage directly.
//$identity = $token->getDetails();
//$order = $payum->getStorage($identity->getClass())->find($identity);
// or Payum can fetch the model for you while executing a request (Preferred).
$payment->execute($status = new GetHumanStatus($token));
$order = $status->getFirstModel();
// you have order and payment status
// so you can do whatever you want for example you can just print status and payment details.
return new JsonResponse(array(
'status' => $status->getValue(),
'response' => array(
'order' => $order->getTotalAmount(),
'currency_code' => $order->getCurrencyCode(),
'details' => $order->getDetails(),
),
));
}
/**
* #return RegistryInterface
*/
protected function getPayum()
{
return $this->get('payum');
}
/**
* #return GenericTokenFactoryInterface
*/
protected function getTokenFactory()
{
return $this->get('payum.security.token_factory');
}
}
This is my Orders Entity
<?php
namespace ClickTeck\featuresBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use ClickTeck\featuresBundle\Model\Orders as BasePaymentDetails;
/**
* Orders
*/
class Orders extends BasePaymentDetails
{
/**
* #var integer
*/
protected $id;
private $number;
private $description;
private $client_email;
private $client_id;
private $total_amount;
private $currency_code;
protected $details;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set number
*
* #param integer $number
* #return Orders
*/
public function setNumber($number)
{
$this->number = $number;
return $this;
}
/**
* Get number
*
* #return integer
*/
public function getNumber()
{
return $this->number;
}
/**
* Set description
*
* #param string $description
* #return Orders
*/
public function setDescription($description)
{
$this->description = $description;
return $this;
}
/**
* Get description
*
* #return string
*/
public function getDescription()
{
return $this->description;
}
/**
* Set client_email
*
* #param string $clientEmail
* #return Orders
*/
public function setClientEmail($clientEmail)
{
$this->client_email = $clientEmail;
return $this;
}
/**
* Get client_email
*
* #return string
*/
public function getClientEmail()
{
return $this->client_email;
}
/**
* Set client_id
*
* #param string $clientId
* #return Orders
*/
public function setClientId($clientId)
{
$this->client_id = $clientId;
return $this;
}
/**
* Get client_id
*
* #return string
*/
public function getClientId()
{
return $this->client_id;
}
/**
* Set total_amount
*
* #param float $totalAmount
* #return Orders
*/
public function setTotalAmount($totalAmount)
{
$this->total_amount = $totalAmount;
return $this;
}
/**
* Get total_amount
*
* #return float
*/
public function getTotalAmount()
{
return $this->total_amount;
}
/**
* Set currency_code
*
* #param string $currencyCode
* #return Orders
*/
public function setCurrencyCode($currencyCode)
{
$this->currency_code = $currencyCode;
return $this;
}
/**
* Get currency_code
*
* #return string
*/
public function getCurrencyCode()
{
return $this->currency_code;
}
/**
* Set details
*
* #param string $details
* #return Orders
*/
public function setDetails($details)
{
$this->details = $details;
return $this;
}
/**
* Get details
*
* #return string
*/
public function getDetails()
{
return $this->details;
}
}
This is my PaymentToken Entity
<?php
namespace ClickTeck\featuresBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Payum\Core\Model\Token;
/**
* PaymentToken
*/
class PaymentToken extends Token
{
}
This is my Orders model
<?php
namespace ClickTeck\featuresBundle\Model;
use Payum\Core\Model\ArrayObject;
class Orders extends ArrayObject
{
protected $id;
/**
* #return int
*/
public function getId()
{
return $this->id;
}
}
Now when I call the Action
preparePaypalExpressCheckoutPaymentAction via route
I get redirected to make the payment
I can see the response in doneAction
Very neat library. Took me a while to figure it out and I am glad it works now. I am sure i have alot more to learn about Payum and I hope someone can confirm if this is the right way :)
This describes my current schema:
/**
* #MongoDB\Document(repositoryClass="St\AppBundle\Repository\TaxiStateRepository", requireIndexes=true)
* #MongoDB\Index(keys={"location"="2d"})
*/
class TaxiState
{
/**
* #MongoDB\ReferenceOne(targetDocument="Taxi", simple=true, inversedBy="taxiState")
* #MongoDB\Index
*/
protected $taxi;
..
}
/**
* #MongoDB\Document(repositoryClass="St\AppBundle\Repository\TaxiRepository", requireIndexes=true)
*/
class Taxi
{
/**
* #MongoDB\ReferenceOne(targetDocument="Driver", simple=true)
* #MongoDB\Index
*/
protected $driver;
..
}
/**
* #MongoDB\Document(repositoryClass="St\AppBundle\Repository\DriverRepository", requireIndexes=true)
*/
class Driver
{
/**
* #MongoDB\EmbedOne(targetDocument="DriverAccount")
* #MongoDB\Index
*/
protected $driverAccount;
..
}
/** #MongoDB\EmbeddedDocument */
class DriverAccount
{
/**
* #MongoDB\String
* #Assert\NotBlank()
* #Assert\Choice(choices = {"enabled","disabled"}, message="please chose a valid status"); * #MongoDB\Index
*/
protected $status;
I basically want to run a query that filters out disabled driver accounts.. something like this:
return $this->createQueryBuilder()
->field('taxi.driver.driverAccount.status')->equals("enabled")
->getQuery()
->getSingleResult();
it complains that it doesn't have an index taxi.driver etc.. I spent all day looking at by directional reference documentation in doctrine but the examples are so sparse.. help?
For reference.. this was the query that worked right before i introduced that crazy line:
return $this->createQueryBuilder()
->field('status')->equals('available')
->field('taxi')->notIn($taxiObj)
->field('location')->near((float)$location->getLongitude(), (float)$location->getLatitude())
->distanceMultiplier(self::EARTH_RADIUS_KM)
->maxDistance($radius/111.12)
->getQuery()
->execute();
Just in case you were wondering how I "resolved" this (it's a very hacky answer.. but oh well you do what you gotta do right?) this is what I got:
/**
* Find near enabled taxi without rejected request taxi
*
* #param Document\Location $location
* #param int $radius
* #param array $taxis
* #return Document\TaxiState
*/
public function findEnabledNearTaxiWithoutRejectRequest(Document\Location $location, $radius = self::SEARCH_RADIUS, $taxis = array(), $logger)
{
$taxiObj = array_map(function ($item) {
return new \MongoId($item);
}, $taxis);
//ST-135 change to near, spherical, distanceMultiplier and maxDistance in KM
$allTaxiStates = $this->createQueryBuilder()
->field('status')->equals('available')
->field('taxi')->notIn($taxiObj)
->field('location')->near((float)$location->getLongitude(), (float)$location->getLatitude())
->distanceMultiplier(self::EARTH_RADIUS_KM)
->maxDistance($radius/111.12)
->getQuery()
->execute();
$this->addIdsOfDisabledTaxiStates($taxiObj, $allTaxiStates);
if (count($taxiObj) > 0) {
$logger->info("There are ".count($taxiObj)." taxis excluded while looking for taxis to respond to a requst: ".$this->getMongoIdsStr($taxiObj));
}
return $this->createQueryBuilder()
->field('status')->equals('available')
->field('taxi')->notIn($taxiObj)
->field('location')->near((float)$location->getLongitude(), (float)$location->getLatitude())
->distanceMultiplier(self::EARTH_RADIUS_KM)
->maxDistance($radius/111.12)
->getQuery()
->getSingleResult();
}
/**
* Get the Mongo Ids of disabled taxi States
*
* #param $ids existing array of ids we want to append to (passed by reference)
* #param $taxiStates array of Document\TaxiState
* #return array of MongoIds of disabled taxi states
* #author Abdullah
*/
private function addIdsOfDisabledTaxiStates(&$ids, $taxiStates)
{
foreach ($taxiStates as $taxiState) {
if ($taxiState->getTaxi()->getDriver()->getDriverAccount()->getStatus() != DriverAccountModel::STATUS_ENABLED) {
$mongoId = new \MongoId($taxiState->getTaxi()->getId());
array_push($ids, $mongoId);
}
}
return $ids;
}