I have a problem, while deleting an entry in a m:n-table. I tried this solution, but I get the error: "ContextErrorException: Catchable Fatal Error: Argument 1 passed to Pso\ProjectBundle\Entity\Project::removeUser() must be an instance of Pso\LogBundle\Entity\User, string given, called in C:\xampp\htdocs\pso\src\Pso\ProjectBundle\Controller\ProjectController.php on line 59 and defined in C:\xampp\htdocs\pso\src\Pso\ProjectBundle\Entity\Project.php line 452"
I have a Class Project with the function:
/**
* Remove users
*
* #param \Pso\LogBundle\Entity\User $users
*/
public function removeUser(\Pso\LogBundle\Entity\User $users)
{
$this->users->removeElement($users);
}
Now I want to delete an entry from the table project_user. This table implements the n:m-relationship from user and project
Im my Controller I tried to adapt the linked solution:
public function deleteUserProjectAction($id, $projectid, Request $request)
{
$em = $this->getDoctrine()->getManager();
$project = $em->find('PsoProjectBundle:Project', $projectid);
$project->removeUser($id);
$em->persist($project);
$em->flush();
}
$id is the id of the user in the n:m table and $projectid the related project. Any hint for solution would be appreciated.
The error is extremly explicit. You are giving to the removeUser() function a string which is the user's id whereas the expected parameter type is a User.
You must retrieve the user from the DB thanks to $id and then pass this user to the function.
Related
Hello my website is made by symfony and mysql.
Now im stuck in this error.
publisher_id cannot be null.
this errror means that publisher_id column of volume table can not be null.
this error is correct but i set value to publisher_id
and i did var_dump like below and i got correct Entity.
$volume = new Volume(); //instanciate Volume Entity.
$volume->setISBN($ISBN);
$volume->setStorePublisher($publisher); //set Publisher Entity to Volume Entity.
var_dump($publisher->getId()); //correct id shown.why no publisher id???
$volume->setCreatedAt(Context::now());
$volume->setUpdatedAt(Context::now());
$em = Context::getEntityManagerWrite();
$em->transactional(function (EntityManager $em) use (&$volume) {
$volume = $em->merge($volume); // i got error here.why ??
$em->flush();
//....
}
Your Error:
To begin with your problem you're trying to merge an unmanaged Entity,
Persist it inside the em first as such :
$volume = new Volume();
$volume->setISBN($ISBN);
$volume->setStorePublisher($publisher);
$volume->setCreatedAt(Context::now());
$volume->setUpdatedAt(Context::now());
$em->persist($volume);
// do stuff
FYI:
in you entity add the __construct method to remove this ugly createAt()from your controller
class Volume {
public function __construct()
{
$this->setCreateAt(new \DateTime());
}
}
For the updateAt() you can use services as shown in the Doc. The objective is to keep your Controlleras light as possible.
I've a Symfony 4 project with User entity and SoldeConges Entity.
An user has a SoldeConges collection.
But when I dump the $user->getSoldeConges(), the collection is empty.
My User entity :
/**
* #ORM\OneToMany(targetEntity="App\Entity\SoldeConges", mappedBy="user", orphanRemoval=true)
*/
private $soldeConges;
/**
* #return Collection|SoldeConges[]
*/
public function getSoldeConges(): Collection
{
return $this->soldeConges;
}
And my user has 3 soldeConges :
PhpMyAdmin SoldeConge table :
And when I make a dump in my controller for my User (which is the user number 1) :
$soldeConges = $this->getUser()->getSoldeConges();
dump($soldeConges);
I've :
So, why can not access to my User SoldeConges collection ?
1)To get your soldeConges (this is symfony 3 code, adapt it to 4 ;-) ):
$em = $this->getDoctrine()->getManager();
$soldeCongesRepository= $em->getRepository('AppSoldeConges:SoldeConges');
$soldeConges = $soldeCongeRepository->findBy(['userId'=>$this->getUser()->getId()]);
2)It may be due to Doctrine lazy loading.
Try fetch="EAGER" (it's LAZY by default):
* #ORM\OneToMany(targetEntity="App\Entity\SoldeConges", mappedBy="user", orphanRemoval=true, fetch="EAGER")
Doctrine loads the whole collection in once IF you try to access it. A dump is the memory model at the moment where you place your dump() statement.
If you should render the collection first (or even only if you use the count() method on the collection) and then use the dump() statement you will see that your collection has been loaded. This is the system called lazy loading. It will execute a second query when needed. But as you may know if two queries could get one query then it should be better and faster.
On the other hand if you have entities with large collections this could get a serious problem. In that case you could use "extra lazy loading". (See the docs)
Anyway if you want to get your collections loaded immediately with your entities then you could use your own DQL query that have one or more JOINS. Below an example of your Repository with a new function called findAllWithJoin. Call that function from your controller instead of findAll().
namespace App\Repository;
use App\Entity\User;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Common\Persistence\ManagerRegistry;
class UserRepository extends ServiceEntityRepository
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, User::class);
}
public function findAllWithJoin()
{
$entityManager = $this->getEntityManager();
$query = $entityManager->createQuery('SELECT u, sc FROM User u JOIN u.soldeConges sc');
return $query->execute();
}
}
I have a OneToMany Unidirectional relationship between an "Employee" and "Status".
There is then also a ManyToMany biderectional relationship between "Employee" and "Documents".
When I have my a Document, i am trying to find all related employees ($Document->getEmployees()) and then "filter" (using ->matching(Criteria)) by the "Status"
I keep getting the below error:
2018-04-05T14:35:19+00:00 [error] Error thrown while running command "app:expiration-check". Message: "Notice: Undefined index: Status"
In DefaultQuoteStrategy.php line 39:
Notice: Undefined index: Status
Here is the Code i am using:
$Employees = $Document->getEmployees()->matching(
Criteria::create()
->andWhere(Criteria::expr()->eq('Status',$this->GlobalSettings->getApprovedEmployeeStatus()))
);
Interestingly enough, the exact same criteria works if i am using the Employee Repository
$Employees = $this->em->getRepository(Employee::class)->matching(
Criteria::create()
->andWhere(Criteria::expr()->eq('Status',$this->GlobalSettings->getApprovedEmployeeStatus()))
);
Matching static fields also works fine.
$Employees = $Document->getEmployees()->matching(
Criteria::create()
->andWhere(Criteria::expr()->eq('FirstName',"Keven"))
);
Here is the Status Column defintion
/**
* #ORM\ManyToOne(targetEntity="Entity\Accounts\EmployeeStatus")
* #ORM\JoinColumn(name="StatusId", referencedColumnName="id", nullable=false)
*/
private $Status;
Here is the Employees Defintion (on Document Entity)
/**
* #ORM\ManyToMany(targetEntity="Entity\Accounts\Employee", mappedBy="Documents")
*/
private $Employees;
/**
* Constructor
*/
public function __construct()
{
parent::__construct();
$this->Employees = new \Doctrine\Common\Collections\ArrayCollection();
}
and Here is the getEmployees() (also on Document)
/**
* Get employees.
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getEmployees()
{
return $this->Employees;
}
To manage ManyToMany relations, doctrine uses Doctrine\ORM\Persisters\Collection\ManyToManyPersister class.
You can see it being used here
Unfortunately, currently in the latest release, v2.6.1, method loadCriteria of this class is lacking the feature to use relation fields. Only static fields are supported.
Looking at the master branch currently, this support has been added: Doctrine\ORM\Persisters\Collection\ManyToManyPersister as of today
but it is not part of a release yet. Also having a quick look at 2.7 branch it does not look it will be there.
I am not sure whether you could use the master branch with symfony `s doctrine bundle. I think it will be difficult to get this to work now.
What you could do, is initialize the ManyToMany collection $Document->getEmployees() and then use the matching function, which means that you load all employees and then filter, not lazy load as you would expect.
So do:
$employees = $Document->getEmployees();
$employees->initialize();
$employees->matching(
Criteria::create()
->andWhere(Criteria::expr()->eq('Status',$this->GlobalSettings->getApprovedEmployeeStatus()))
);
and put a note to change the code, when the new changes are released.
I am trying to create an action in my controller that handles a null value for category if it's not passed in.
I've tried annotating 2 routes (one without /{category}) but in every case, when I do not supply a category in the URL, Symfony retrieves the 1st category it can find.
#Route("/accounts/{id}/categories/{category}", defaults={"category" = null})
The action definition looks like this:
public function categoryAction(Request $request, Account $account, Category $category)
I have also tried $category = null in the action, but that does not make a difference.
How can I make this action have a $category with a value of null if the category is not defined in the url?
Update:
To be clear, here is the full annotation and function definition with comments on my xdebug results:
/**
* #Route("/accounts/{id}/categories")
* #Route("/accounts/{id}/categories/{category}, defaults={"category" = null}")
*/
public function categoryAction(Request $request, Account $account, Category $category = null)
{
// When I set a breakpoint here, $category is populated with
// the first category result in the database.
// This is when visiting: http://localhost:8000/accounts/1/categories
You can define multiple routes for same actions, maybe try something like :
/**
* #Route("/accounts/{id}/categories")
* #Route("/accounts/{id}/categories/{category}")
* #Template()
*/
public function categoryAction(Request $request, Account $account, Category $category)
{
And if you try to access /accounts/{id}/categories, $category will be null
I believe this is the change you should make:
/**
* #Route("/accounts/{id}/categories", defaults={"category" = null}")
* #Route("/accounts/{id}/categories/{category})
*/
public function categoryAction(Request $request, Account $account, Category $category)
{
...
Can you try it and let us know? I haven't tested it, but I think it's right.
I find it somewhat annoying to have to constantly use #var on getUser. It seems sloppy.
So I was thinking about starting to use this instead
<?php
// in the controller
$user = Customer::isCustomer($this->getUser());
// in the entity
/**
* #param Customer $user
*
* #return Customer
*/
public static function isCustomer(Customer $user)
{
return $user;
}
Is this a good idea? Bad idea? Horrible idea?
A type hint is the better option in this case.
Why would you write more code by adding checks manually rather than adding a simple type hint to your param.
Your four lines of codes representing two conditions give exactly the same result as:
/**
* #param Customer|null $user
*
* #return Customer|null
*/
public static function isCustomer(Customer $user = null)
{
// If $user is null, it works
// If $user is a Customer instance, it works
// If it's other, an exception is thrown
return $user;
}
Type hinting optimises and give more readability to a code.
It's a convention in symfony2, php and more.
It's commonly used as a constraint (or contract) with you and your method.
Also, it's the only alternative for an interface or an abstract class to add requirement to a parameter, because they don't have a body, and so cannot write conditions.
Update
In SensioLabs Insight, Object type hinting represents a warning using the following message :
The parameter user, which is an object, should be typehinted.
Because the verb should is used, I consider it's not a mandatory requirement, just a very good practice in case of it doesn't cause any problem.
Also, you can use the example you given without making your code horrible.