[DDC-222] Create unit tests for CLI components Created: 22/Dec/09  Updated: 30/Oct/10

Status: Reopened
Project: Doctrine 2 - ORM
Component/s: ORM
Affects Version/s: 2.0-ALPHA3
Fix Version/s: 2.x
Security Level: All

Type: Task Priority: Critical
Reporter: Roman S. Borschel Assignee: Guilherme Blanco
Resolution: Unresolved Votes: 0
Labels: None

Issue Links:
Reference
is referenced by DDC-359 Specified, but empty CLI Options --op... Resolved

 Comments   
Comment by Roman S. Borschel [ 19/May/10 ]

Whats the status here? Do we have any?

Comment by Guilherme Blanco [ 19/May/10 ]

Since we moved to Symfony Console I don't think this is needed anymore.
The purpose of this ticket was actually to test our own CLI support, which was dropped.

I'm closing the ticket due to this. Reopen if you have any other comment.

Comment by Benjamin Eberlei [ 20/May/10 ]

I think we do need some basic functional tests of our Commands, they have been subject to many bugs in the past becaues they are not tested.

Comment by Benjamin Eberlei [ 19/Jun/10 ]

Fixed another fatal error in the command due to missing namespace dependency. We need tests for all the commands, there have been dozens of issues on these things so far.

This commit shows a simple approach on how testing is easily possible for symfony commands:

http://github.com/doctrine/doctrine2/commit/51e6681934a7cf4448b85c5670c04045f66c6056

Comment by Roman S. Borschel [ 26/Aug/10 ]

Can we expect some more tests for beta4 or is it unlikely that you find the time? Should we move this further back or does someone else want to step in?





[DDC-1415] EventListener delegate on entity basis Created: 11/Oct/11  Updated: 20/Dec/11

Status: Reopened
Project: Doctrine 2 - ORM
Component/s: None
Affects Version/s: None
Fix Version/s: 2.x
Security Level: All

Type: New Feature Priority: Major
Reporter: Benjamin Eberlei Assignee: Benjamin Eberlei
Resolution: Unresolved Votes: 0
Labels: None


 Comments   
Comment by Benjamin Eberlei [ 12/Dec/11 ]

Removed from master, as i dont like the api at all

Comment by Guilherme Blanco [ 20/Dec/11 ]

Updating fix version





[DDC-1924] Let SQLFilters know the query type it is being applied to Created: 13/Jul/12  Updated: 13/Jul/12

Status: Reopened
Project: Doctrine 2 - ORM
Component/s: ORM
Affects Version/s: None
Fix Version/s: None
Security Level: All

Type: Improvement Priority: Major
Reporter: Jan Knudsen Assignee: Benjamin Eberlei
Resolution: Unresolved Votes: 0
Labels: None


 Description   

I'm making an access control system and would like to automatically filter all queries based current user, targetEntity type and query type. Query type is relevant as different permissions are needed by the user for SELECT, UPDATE, DELETE and INSERT queries.

I can access the first two things in my filter easily enough, but I cannot find a way to have the filter know what type of query the filter is being applied to.



 Comments   
Comment by Benjamin Eberlei [ 13/Jul/12 ]

The Filter API only makes sense for SELECT clauses. Doctrine itself does not use DQL to do updates internally, so you need to use other mechanisms (EventListener) to prevent this operations if they are not allowed for a user.

Comment by Jan Knudsen [ 13/Jul/12 ]

But I can make custom DQL to update rows and would like to automatically filter this too.

e.g. $em->createQuery("UPDATE SomeEntity se SET se.field = "updated!")->execute();

The lifecycle events preUpdate etc. are not called when doing custom DQL queries.

Maybe it is bad practice and discouraged to do updates, inserts and deletes as custom DQL queries, but I would like to ensure that the other people in my organization can't accidentally bypass the Access Control, even if they make use of such bad practice.

And if the filter API only makes sense for Select statements, why are filters applied to update/delete/etc. statements too?

Comment by Benjamin Eberlei [ 13/Jul/12 ]

Well, they are applied to DQL UPDATE/DELETE. But not not UPDATE/DELETE that works through the internals of Doctrine. So yes, you can use it to filter DQL DELETE/UPDATE, but doctrine does not do that internally.

So you have to have two strategies, a DQL/SQL Filter - and Lifecycle events.

Comment by Jan Knudsen [ 13/Jul/12 ]

Which is fine by me. I already implemented the checks using lifecycle events before opening this issue. The access control is automatically handled when using the entitymanager and not custom DQL.

Now I would also like to filter the custom DQL, but currently I can't, because as originally stated, the filter needs to know which type of query it is being applied to.





[DDC-1698] Inconsistent proxy file name & namespace result in __PHP_Incomplete_Class when unserializing entities Created: 13/Mar/12  Updated: 06/Jan/13

Status: Reopened
Project: Doctrine 2 - ORM
Component/s: ORM
Affects Version/s: 2.2, 2.2.1
Fix Version/s: 2.2.2
Security Level: All

Type: Documentation Priority: Major
Reporter: Benjamin Morel Assignee: Benjamin Eberlei
Resolution: Unresolved Votes: 0
Labels: None
Environment:

Irrelevant



 Description   

Starting with Doctrine 2.2, the Proxy classes have inconsistent naming with their file name, which raises problems with class autoloading.
For example, a class named Application\Model\User creates the following proxy class:

Application\Proxy\__CG__\Application\Model\User

This class is located in the following file:

Application/Proxy/__CG__ApplicationModelUser.php

But whe we serialize such an entity, then unserialize it in another session, the framework autoloader expects the class to be located in:

Application/Proxy/__CG__/Application/Model/User.php

But it is not.
As a result, a __PHP_Incomplete_Class is created instead of the expected proxy class.

I'm not sure whether this is an intended behavior, but I would assume this is a bug.



 Comments   
Comment by Benjamin Morel [ 13/Mar/12 ]

It looks like there is an even broader problem with the new _CG_ prefix; the PSR-0 standard for autoloading states that the underscores should be handled this way:

\namespace\package\Class_Name => {...}/namespace/package/Class/Name.php

Which means that in the above example, it could even expect the file to be located in:

Application/Proxy///CG///Application/Model/User.php

... which is far away from the actual location.
Upgrade to 2.2 broke this code, for us.

Comment by Benjamin Eberlei [ 14/Mar/12 ]

Proxy classes do not follow PSR-0. For the case unserializing objects we should provide an extra autoloader i guess.

See here how symfony does it https://github.com/doctrine/DoctrineBundle/blob/master/DoctrineBundle.php#L57

Comment by Benjamin Eberlei [ 14/Mar/12 ]

See https://github.com/doctrine/doctrine2/commit/9b4d60897dfc7e9b165712428539e694ec596c80 and https://github.com/doctrine/orm-documentation/commit/01381fae1ff3d4944086c7cfe46721925bf6ca15

Comment by Benjamin Morel [ 14/Mar/12 ]

Thanks for the quick fix, Benjamin.
However, I have to admit that I'm not fully happy with the fix, as we (and probably many others) are not using the Doctrine autoloader.
I supposed that the purpose of PSR-0 was precisely not to be tied to a particular autoloader implementation, and this benefit is lost with this version of Doctrine.

You mentioned in the doc that the proxies are not PSR-0 compliant "for implementation reasons"; as this was working fine before 2.2, could you please explain what requirement prevents Doctrine from keeping the previous naming convention?

Comment by Benjamin Eberlei [ 29/Mar/12 ]

In 2.1 the proxies are not PSR-0 compatible themselves, however their class naming is simpler.

In 2.2 we changed proxy names so that you can derive the original name of the proxy by searching for the _CG_ flag. This flag obviously contains the __ chars that some PSR autoloaders detect as directory seperators. I agree this is an unfortunate decision, but it was done this way.

I do think however that we can automatically register the proxy atuoloader (if not yet done) in EntityManager#create(). This would hide this fact from developers automatically.

Comment by Benjamin Morel [ 29/Oct/12 ]

@Benjamin Eberlei
In 2.3 we still have to manually call Autoloader::register() before unserializing entities that may contain proxies.
So EntityManager::create() still doesn't register it. Is there a plan to add this feature?

Comment by Benjamin Eberlei [ 06/Jan/13 ]

Benjamin Morel Not at the moment, seems too dangerous for me since it might produce race conditions. This should really be done in the bootstrap of the system.

We need to document this though.

Comment by Benjamin Morel [ 06/Jan/13 ]

Ok, thanks for your answer!





[DDC-2210] PHP warning in ProxyFactory when renaming proxy file Created: 20/Dec/12  Updated: 28/Mar/13

Status: Reopened
Project: Doctrine 2 - ORM
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Improvement Priority: Major
Reporter: Matthieu Napoli Assignee: Marco Pivetta
Resolution: Unresolved Votes: 0
Labels: None
Environment:

Windows



 Description   

Getting a PHP Warning:

rename(**/models/Proxies_CGAF_Model_Component_Group.php.50d2dd2c079bb9.35271255,**/models/Proxies__CG_AF_Model_Component_Group.php):

in ProxyFactory line 194.

I haven't more information in the warning.

This is the moment when the ProxyFactory writes the proxy to a temporary file and then tries to rename the temp file to the correct file.

This warning appears randomly, but mostly on pages with lots of concurrent AJAX requests. I guess this happens because several requests try to write the proxy file at the same time. I get this warning but the app works fine.

This happens in dev environment, on a Windows machine.

I don't know why rename generates a warning, it should just return false... The doc doesn't say anything about warnings (except for long file names, but I checked even with the full path this is around 135 characters, not 255).



 Comments   
Comment by Benjamin Eberlei [ 22/Dec/12 ]

Thats why you shouldn't generate proxies at runtime. The problem happens on windows, because the atomic rename operation doesn't work as perfectly there as on linux.

We cannot fix this in Doctrine.

Comment by Matthieu Napoli [ 24/Dec/12 ]

Benjamin Eberlei What do you mean "you shouldn't generate proxies at runtime"? I'm not in production, this is in dev. And I'm using the default configuration.

What I don't understand is why will Doctrine regenerate proxies on every request? The warning is reproductible, and even when no PHP entity has been touched.

Comment by Matthieu Napoli [ 27/Dec/12 ]

Benjamin Eberlei To simplify my previous message (I don't want to bury you under questions) I'll sum it up like that:

What can I do?

Thanks!

Comment by Matthieu Napoli [ 28/Feb/13 ]

Benjamin Eberlei ping: what can be done?

Can we suppress the error with @rename($tmpFileName, $fileName); ?

https://github.com/doctrine/common/blob/master/lib/Doctrine/Common/Proxy/ProxyGenerator.php#L287

I can make a PR if you think that's a valid solution.

Comment by Marco Pivetta [ 28/Feb/13 ]

Matthieu Napoli no, if you have warnings, please disable them via ini setting. With error suppression there, we may have further problems identifying more serious issues.

About proxy generation: that happens EVERY time in dev environments. Generate them once and disable it afterwards.

Comment by Matthieu Napoli [ 28/Feb/13 ]

Marco Pivetta OK I can disable the auto generation then (I'll have to remember to regenerate them when I edit the model).

Thanks for the feedback

Is that possible to make those proxies generate only if the entity file has been modified since the last generation? (only asking if can and should be done, I can look for implementing it myself if that's the case)

Comment by Marco Pivetta [ 28/Feb/13 ]

Matthieu Napoli that would be very obnoxious when changing entities often. I wouldn't do that (generating only if not already available)

Comment by Matthieu Napoli [ 28/Feb/13 ]

Marco Pivetta Yes but for now they are regenerated at every request when in dev mode (at least with the default configuration http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/configuration.html#obtaining-an-entitymanager)

Which one is worse: generating every proxy class at every request, or generate only those which changed (in dev environment of course, not prod)?

If neither of these options are good (i.e. auto generation should be disabled), I don't understand why the docs say to enable auto generation when in dev environment.

Comment by Marco Pivetta [ 28/Feb/13 ]

Matthieu Napoli that's because in dev environments you shouldn't care about that one exception (usually happens when you got concurrent requests).

It is worse to generate only on changes: that's a lot of additional checks, variables to keep in memory and additional logic that is not needed.

Let's keep it as it is (generating at each request) for dev environments: works fine

Another (eventual) solution for dev environments would be not to write the proxy file, but to eval it.

Comment by Matthieu Napoli [ 28/Feb/13 ]

eval it would be a good solution IMO, no more "woops the directory is not writable" and it's more neutral for the user filesystem (but not as easy to debug). But OK, I see what you mean, it works let's keep it that way.

Actually the problem on my setup is that PHP errors are turned into exceptions, so on an (poorly designed) AJAX treeview (lots of nodes to load => lots of requests), I end up with some nodes not loaded because of the exception. And it feels weird to either silently log all PHP warnings or silently ignore the specific warning for the rename.

Comment by Marco Pivetta [ 28/Feb/13 ]

Matthieu Napoli I'd go with `eval` then. Needs refactoring of the abstract proxy factory and of the proxy generator (proxy generator should no longer write files).

Comment by Marco Pivetta [ 28/Feb/13 ]

Re-opening: the proxy factory could directly `eval()` the produced proxy code. The ProxyGenerator should no longer write the generated files to disk automatically.

Comment by Matthieu Napoli [ 28/Mar/13 ]

I've opened a PR: https://github.com/doctrine/common/pull/269





[DDC-2405] Changing strategy generates bad query. Created: 19/Apr/13  Updated: 21/Apr/13

Status: Reopened
Project: Doctrine 2 - ORM
Component/s: None
Affects Version/s: None
Fix Version/s: None
Security Level: All

Type: Bug Priority: Major
Reporter: Van Rotemberg Assignee: Benjamin Eberlei
Resolution: Unresolved Votes: 0
Labels: None


 Description   

For (unit, acceptance, functional) testing purpose I need to change the strategy of my GameStuff Entity class.

In previous version is was using php instruction below, but since doctrine orm 2.3, it doesn't work anymore.

$orm->getClassMetaData('Entities\GameStuff')->setIdGeneratorType(\Doctrine\ORM\Mapping\ClassMetadata::GENERATOR_TYPE_NONE);

will trigger:

Doctrine\DBAL\DBALException: An exception occurred while executing 'INSERT INTO vbank_accounts (game_id, updated_at, created_at) VALUES (?, ?, ?)' with params

{"1":1000010, "2":0,"3":"2013-04-19 17:16:05","4":"2013-04-19 17:16:05"}

:

SQLSTATE[HY093]: Invalid parameter number: number of bound variables does not match number of tokens



 Comments   
Comment by Benjamin Eberlei [ 20/Apr/13 ]

The problem is that changing ClassMetadata after generating it from the cache is not really supported and depends on the Internal State of other classes. Have you tried creating a completly new EntityManager and then directly setting this? It could be that the SQL for the entity was already generated inside Doctrine, with the ID Generator information at IDENTITY_AUTO.

Comment by Van Rotemberg [ 21/Apr/13 ]

> The problem is that changing ClassMetadata after generating it from the cache is not really supported

Yeah, it is a problem indeed, why set ticket status to resolved ?
Do you think it's normal to have a public method that trigger a fatal error ?

Please fix it or put setIdGeneratorType as private, or AT LEAST add a context exception ...

Comment by Marco Pivetta [ 21/Apr/13 ]

Almost every interaction with metadata outside the `loadClassMetadata` event will cause unexpected problems. I don't think throwing an exception there helps in any way.

Comment by Van Rotemberg [ 21/Apr/13 ]

@marco pivetta

The generation of the actual exception comes from DBALException on the query excetion and point a bad generated query (Invalid parameter number),
when the problem comes from setting ClassMetada, and concerns a problem of cache generated after loadClassMetadata.

Adding an exception is just the fast way pointing where the problem comes from and that "setting metadata after loadMetadata is not supported anymore". (It will spare developper's time that used to set metadata, but also help future contribution)

> Please fix it or put setIdGeneratorType as private, or AT LEAST add a context exception ...
Note: BTW, my favorite solution would be to fix it (re-generate cache, or edit cache, or disable cache or whatever)





[DDC-2052] Custom tree walkers are not allowed to add new components to the query Created: 02/Oct/12  Updated: 14/May/13

Status: Reopened
Project: Doctrine 2 - ORM
Component/s: DQL
Affects Version/s: 2.3
Fix Version/s: 2.4

Type: Improvement Priority: Major
Reporter: Łukasz Cybula Assignee: Benjamin Eberlei
Resolution: Unresolved Votes: 0
Labels: dql


 Description   

Custom tree walkers have freedom in modifying the AST but when you try to add a new query component (i.e. new join in walkSelectStatement() ) to the AST then the SqlWalker throws an exception because it does not has the new component in its _queryComponents array. I see two possible ways to resolve this:
1. Modify the Parser class in order to allow tree walkers to modify queryComponents and pass changed queryComponents to the SqlWalker
2. Improve SqlWalker so it can extract and prepare needed information about queryComponent based on AST when it does not have them.



 Comments   
Comment by Benjamin Eberlei [ 06/Oct/12 ]

Ok this is much more complicated to allow then i thought. The problem is that the QueryComponents are passed by value, as an array, not by reference. That prevents changing them because this change wouldn't be visible in the output walker.

I can add a method to allow this in the OutputWalker for now, but generally this requires a bigger refactoring on the Query Components.

Comment by Benjamin Eberlei [ 06/Oct/12 ]

Added setQueryComponent() in SQL Walker to allow modification in output walker.

Comment by Łukasz Cybula [ 08/Oct/12 ]

I'm afraid that this doesn't solve the initial problem at all. I'll try to describe it in more details to show what I mean. Suppose we have two doctrine extensions each of which contain its own tree walker. Each of these tree walkers need to modify AST and add new component to it (joined with some component already existing in the query). The first problem is that each tree walker has its own queryComponents array which is not passed between them, although they not necessary need to use queryComponents - they could use only AST. The second, bigger problem is that the Parser class does not know anything about modifications of queryComponents in tree walkers and cannot pass modified version to the OutputWalker. The goal of submitting this issue was to allow adding new components to the query in tree walkers which is not achievable by your fix. I think it may be the first step in the right direction. Maybe TreeWalkerAdapter should have public method getQueryComponents() which would be used by the Parser to pass modified queryComponents between different tree walkers and finally to the OutputWalker ? This would not break backward compatibility and solve this issue. What do you think about it?

Comment by Łukasz Cybula [ 08/Oct/12 ]

I've tried to implement the solution mentioned in previous comment but it's also not so clean and easy as I thought. Each tree walker (including TreeWalkerChain) would have to implement getQueryComponents() and setQueryComponent($alias, array $component) methods. The same with SqlWalker, so the TreeWalker interface should have these methods, which would break BC in some way (walkers that do not inherit from SqlWalker or TreeWalkerAdapter will fail to compile). So maybe my first solution (PR #464) is not so bad for now? In the future queryComponents could be replaced by a special object or could be passed by a reference to allow modifications.

Comment by Benjamin Eberlei [ 09/May/13 ]

Marked as improvement as its not a bug.

A solution might probably implement an object holding all the QueryComponent, implementing ArrayAccess. So that way the state can be shared.

Comment by Marco Pivetta [ 14/May/13 ]

Just hit this while developing an ast walker... Will look into it too since I need it more than soon.

Comment by Marco Pivetta [ 14/May/13 ]

As a VERY UGLY workaround, I used a static variable and a custom sql walker in combination with my AST walker.


namespace Comcom\Versioning\ORM\Query;


use Doctrine\ORM\Query\SqlWalker;

class WorkaroundSqlWalker extends SqlWalker
{
    public function __construct($query, $parserResult, array $queryComponents)
    {
        parent::__construct($query, $parserResult, $queryComponents);

        foreach (VersionWalker::$additionalAliases as $alias => $value) {
            $this->setQueryComponent($alias, $value);
        }
    }
}




[DDC-2461] [GH-673] Namespace based command names Created: 17/May/13  Updated: 17/May/13

Status: Reopened
Project: Doctrine 2 - ORM
Component/s: None
Affects Version/s: None
Fix Version/s: None
Security Level: All

Type: Bug Priority: Major
Reporter: Doctrine Bot Assignee: Marco Pivetta
Resolution: Unresolved Votes: 0
Labels: None


 Description   

This issue is created automatically through a Github pull request on behalf of hell0w0rd:

Url: https://github.com/doctrine/doctrine2/pull/673

Message:

Symfony console supports auto completion:
``orm:generate:entities`` could called ``o:g:e``



 Comments   
Comment by Doctrine Bot [ 17/May/13 ]

A related Github Pull-Request [GH-673] was closed:
https://github.com/doctrine/doctrine2/pull/673

Comment by Marco Pivetta [ 17/May/13 ]

BC break without advantages

Comment by Doctrine Bot [ 17/May/13 ]

A related Github Pull-Request [GH-673] was reopened:
https://github.com/doctrine/doctrine2/pull/673





[DDC-2235] Single table inheritance discriminator in WHERE when using arbitrary join syntax Created: 11/Jan/13  Updated: 23/May/13

Status: Reopened
Project: Doctrine 2 - ORM
Component/s: ORM
Affects Version/s: 2.3
Fix Version/s: None
Security Level: All

Type: Bug Priority: Major
Reporter: Jordi Forns Assignee: Alexander
Resolution: Unresolved Votes: 3
Labels: None

Issue Links:
Duplicate
duplicates DDC-1940 Doctrine DQL: erroneous sql generatio... Open

 Description   

The condition on the discriminator column is placed in the WHERE clause when using arbitrary join syntax, which renders LEFT JOINs useless.

Given these classes:
A - no inheritance
B1 - abstract, root of a hierarchy, discriminator column is named 'type'
I setup a query builder like this:

$qb->select('a.id AS idA, b.id AS idB')
    ->from('\Entity\A', 'a')
    ->leftJoin('\Entity\B1', 'b', \Doctrine\ORM\Query\Expr\Join::WITH, 'a.something=b.something');
And the SQL Doctrine generates is something like this:
SELECT a.id, b.id FROM a LEFT JOIN b ON (a.something=b.something) WHERE b.type IN ('1', '2', '3')

The problems is that the WHERE condition makes the left join useless.

The condition on the discriminator column should be placed in the JOIN clause to avoid the problem.



 Comments   
Comment by Ondrej Hlavaty [ 10/Feb/13 ]

Can this be somehow worked around? If not, it is really serious problem...

Comment by Jordi Forns [ 18/Feb/13 ]

I couldn't find any workaround.
Trying to force the 'type' condition in the join clause resulted useless as Doctrine would add the 'where' condition regardless.

Comment by Michel Salib [ 22/Mar/13 ]

Easier way to workaround right now, is to declare a OneToMany from class A to class B on a protected field (no need of getter or setter). That way you can do classic join via relationship transversing and then the condition will be placed in the ON part of the query.

Comment by Yuta Konishi [ 01/Apr/13 ]

I could access with below codes. You should use RAW SQL it is easy solution I guess. good luck.

$qb = $em->createQueryBuilder();

$qb->select('a, b')
->from('YourEntity1', 'a')
->leftJoin('YourEntity2', 'b', \Doctrine\ORM\Query\Expr\Join::WITH, 'a.id = b.relationId');

$raw_sql = $qb->where( 
	$qb->expr()->in('a.relationId', $ids)
)
->orderBy('a.updatedAt', 'DESC')
->setMaxResults(10)
->getQuery()->getSQL();

$conn = $em->getConnection();
$stmt = $conn->query($raw_sql);

/* $stmt->fetchAll(); // access as Array */
Comment by Benjamin Eberlei [ 04/Apr/13 ]

Assigned to Alexander

Comment by Benjamin Eberlei [ 14/Apr/13 ]

Duplicate of DDC-1940

Comment by Jordi Forns [ 22/Apr/13 ]

Benjamin: this bug doesn't seem to be a dupe of DDC-1940. Actually that issue doesn't seem to be a bug at all.

As a reminder, the problem in this issue is that when performing arbitrary left joins on entities that are part of a class hierarchy, the discriminator condition is placed in the where clause instead of the join clause. This means that rows that could not be joined will have null values in the discriminator column and thus will not be returned because of the where condition (which will contain something like " where x.discriminator in (1,2,3) ").

Comment by Tom Arnfeld [ 27/Apr/13 ]

Has this issue been resolved elsewhere? From reading over DDC-1940 it doesn't seem to be a duplicate at all. I'm experiencing the same problem as Jordi and can't seem to find a solution. Is there any particular reason the `IN ()` predicate is not a part of the join, but instead placed in the main `WHERE` clause?

Comment by Tom Arnfeld [ 28/Apr/13 ]

I've been looking into the root cause of this bug (or feature..) to try and understand why it's happening, and after trying various possible fixes (a little hard without full understanding of the Doctrine/Query internals) I've ended up with a fix that seems to work well for my use case, at least. I've not run any of the unit tests (I plan to, and may adjust my fix based on that) but the top revision is my change... https://gist.github.com/tarnfeld/a6bb50ec707c7af1c5dc/revisions

Would love some feedback.

Pull request here: https://github.com/doctrine/doctrine2/pull/656

Comment by Jordi Forns [ 29/Apr/13 ]

Tom's fix moves the condition of the discriminator column to the LEFT JOIN, which is exactly what was needed.

Alexander: could you please give it a look?

Comment by Jordi Forns [ 23/May/13 ]

Tom's proposal seems to fix the issue.





[DDC-1283] Possible issue with PersistentCollection#getDelete/InsertDiff() Created: 21/Jul/11  Updated: 20/Sep/12

Status: Reopened
Project: Doctrine 2 - ORM
Component/s: None
Affects Version/s: 2.1
Fix Version/s: 2.4
Security Level: All

Type: Improvement Priority: Minor
Reporter: Glen Ainscow Assignee: Guilherme Blanco
Resolution: Unresolved Votes: 0
Labels: None


 Description   

Using the following code, when you go from (1, 2) to (1), (2) is deleted as expected. However, if you go from (1, 2) to (2), (1) and (2) are deleted and (2) is then inserted. Is this the desired behaviour? (i.e. 2 extra queries)

$bracket->getTournamentLocations()->takeSnapshot();

$col = $bracket->getTournamentLocations()->unwrap();

$col->clear();

foreach ($form->getValue('tournamentLocations') as $id) {
    $col->add($em->getReference('Tournaments_Model_TournamentLocation', $id));
}

$bracket->getTournamentLocations()->setDirty(true);


 Comments   
Comment by Benjamin Eberlei [ 26/Jul/11 ]

First, you are using internal API therefore you are on your own anyways.

This is marked as improvment now, the functionality works, it may just be inefficient.

Comment by Guilherme Blanco [ 09/Dec/11 ]

Hi,

I'm marking issue as invalid because you're conceptually wrong.
What you're trying to do is telling that a collection of new entities is holded by a collection of Persistent entities.
The reference internally of PersistentCollection to ArrayCollection means a lot here.

Correct code would be you to regenerate the collection (a new ArrayCollection) and just assign it to setTournamentLocations($newCollection);

Does this explanation is enough for you?

Cheers,

Comment by Glen Ainscow [ 23/Dec/11 ]

Hi Guilherme,

If I do this:

$locations = new ArrayCollection();

foreach ($form->getValue('tournamentLocations') as $id) {
    $locations->add($em->getReference('Tournaments_Model_TournamentLocation', $id));
}

$bracket->setTournamentLocations($locations);

... then all the records are deleted, before adding the new records. This is inefficient and causes extra, unnecessary write operations.

Can't Doctrine perform diffs when persisting the collection, so that only the necessary deletes and inserts are executed?

Comment by Guilherme Blanco [ 13/Jan/12 ]

We could add it, but I don't think it worth the effort.
Main problem with this one is that we use C-level binary comparison to get the diff. That's what you entities/hash pointers are different.
We would have to write our own diff-comparator for both collections, which would probably slowdown the entire Doctrine.

I'd rather consider that it's not possible to be done at the moment, but I need much more investigation for that. This will be something that I'll probably only do when I look at this issue again with a lot of time (which is really hard to happen).

If you have some spare time, feel free to make some attempts.
Just don't forget to enable performance tests in Doctrine Unit Test suite.





[DDC-1081] Unnecessary JOIN when selecting ManyToMany/Join Table by ID. Created: 27/Mar/11  Updated: 28/Mar/11

Status: Reopened
Project: Doctrine 2 - ORM
Component/s: ORM
Affects Version/s: 2.0
Fix Version/s: None
Security Level: All

Type: Improvement Priority: Minor
Reporter: David Reisch Assignee: Benjamin Eberlei
Resolution: Unresolved Votes: 0
Labels: None


 Description   

With the schema:

 
Image
    @Id
    $id

Tag
    @Id
    $Id

Tag_Image
    @Id
    @OneToOne(targetEntity="Tag")
    @JoinColumn(name="tag")
    $tag

    @Id
    @OneToOne(targetEntity="Image")
    @JoinColumn(name="image")
    $image

Given the following DQL,

    SELECT img
    FROM Image 
    LEFT JOIN img.tags tag
    WHERE tag.id=:tag

Doctrine Generates this SQL

 
    SELECT i0_.id AS id1 
    FROM Image i0_ 
    LEFT JOIN Tag_Image t2_ 
        ON i0_.id = t2_.image 
    LEFT JOIN Tag t1_ 
        ON t1_.id = t2_.tag 
    WHERE t1_.id = 37

Which unncessarily joins against Tag, given that the foreign key Tag.id is also found in Tag_Image.tag.



 Comments   
Comment by Benjamin Eberlei [ 27/Mar/11 ]

This is not a bug, but expected behavior.

You can select against the alias if its on the owning side of the association:

SELECT img
FROM Image img 
WHERE img.tag=:tag

In this case it is not a left join though, if you want a left join you HAVE to join.

Comment by David Reisch [ 27/Mar/11 ]

There is no owning isde of the association, you can clearly see there is an association table/entity.

I can't understand how this behavior is expected. If no properties of Tag are selected for, there is no need to join against Tag since the id is already available via the association table.

Comment by Benjamin Eberlei [ 28/Mar/11 ]

I misread the mappings, sorry, i though its a @OneToOne but its actually an assocition entity with @OneToOnes.

Can you show me the Image::$tags mapping also?

Comment by David Reisch [ 28/Mar/11 ]

That is correct, thanks for taking another look at this.
Sorry I had forgotten to include that information.

Image
    /**
        @Id
    */
    $id

    /**
        @ManyToMany(targetEntity="Tag")
        @JoinTable(name="Tag_Image", 
                            joinColumns={@JoinColumn(name="image")},
                            inverseJoinColumns={@JoinColumn(name="tag")})
    */
    $tags
Comment by Benjamin Eberlei [ 28/Mar/11 ]

The targetEntity is wrong. I suppose it should be Image_Tag or not? If it should be Tag, then you don't need that Image_Tag entity at all.

In that case i have to check if you can use the shortcut notation, however it will again not work with the left join - only inner. This is an assumption the ORM makes and there is not yet code included for the optimization. This is not a bug, but an improvement ticket. The functionality works.

Comment by David Reisch [ 28/Mar/11 ]

No argument on the ticket type...

Ahh, I store some metadata in Tag_Image, which is why I manage it explicitly.

In any case thanks for looking at this.

Comment by Benjamin Eberlei [ 28/Mar/11 ]

If you change the targetEntity to Tag_Image then it might already be enough to get this working without another join.

Comment by David Reisch [ 28/Mar/11 ]

With this change, the original query is invalid:

    LEFT JOIN i.tags t
    WHERE t.id=:tag

Because i.tags of type Tag_Image has no field id

[Semantical Error] line 0, col 138 near 'id=:tag ': Error: Class domain\Tag_Image has no field or association named id

I attempt the logical modification:

    LEFT JOIN i.tags t
    WHERE t.tag=:tag

and get

SELECT i0_.id AS id0
FROM Image i0_ 
LEFT JOIN Tag_Image t1_ ON i0_.id = t1_.image 
LEFT JOIN Tag_Image t1_ ON t1_.id = t1_.tag 
WHERE t1_.tag = 37

SQLSTATE[42000]: Syntax error or access violation: 1066 Not unique table/alias: 't1_





[DDC-450] Add TableGenerator Implementation Created: 20/Mar/10  Updated: 13/Feb/12

Status: Reopened
Project: Doctrine 2 - ORM
Component/s: ORM
Affects Version/s: 2.0-ALPHA4
Fix Version/s: None
Security Level: All

Type: Improvement Priority: Minor
Reporter: Benjamin Eberlei Assignee: Roman S. Borschel
Resolution: Unresolved Votes: 2
Labels: None

Issue Links:
Dependency
depends on DBAL-223 Add DBAL TableGenerator Resolved

 Description   

The TableGenerator Id Generator is not yet implemented, here is some code i came up with:

class TableGenerator extends AbstractIdGenerator
{
    private $_tableName;
    private $_sequenceName;
    private $_allocationSize;
    private $_nextValue;
    private $_maxValue;

    public function __construct($tableName, $sequenceName = 'default', $allocationSize = 10)
    {
        $this->_tableName = $tableName;
        $this->_sequenceName = $sequenceName;
        $this->_allocationSize = $allocationSize;
    }

    public function generate(EntityManager $em, $entity)
    {
        if ($this->_maxValue === null || $this->_nextValue == $this->_maxValue) {
            // Allocate new values
            $conn = $em->getConnection();
            if ($conn->getTransactionNestingLevel() == 0) {

                // use select for update
                $sql = $conn->getDatabasePlatform()->getTableHiLoCurrentValSql($this->_tableName, $this->_sequenceName);
                $currentLevel = $conn->fetchColumn($sql);
                if ($currentLevel != null) {
                    $this->_nextValue = $currentLevel;
                    $this->_maxValue = $this->_nextValue + $this->_allocationSize;

                    $updateSql = $conn->getDatabasePlatform()->getTableHiLoUpdateNextValSql(
                        $this->_tableName, $this->_sequenceName, $this->_allocationSize
                    );
                    
                    if ($conn->executeUpdate($updateSql, array(1 => $currentLevel, 2 => $currentLevel+1)) !== 1) {
                        // no affected rows, concurrency issue, throw exception
                    }
                } else {
                    // no current level returned, TableGenerator seems to be broken, throw exception
                }
            } else {
                // only table locks help here, implement this or throw exception?
                // or do we want to work with table locks exclusively?
            }
        }
        return $this->_nextValue++;
    }
}


 Comments   
Comment by Guilherme Blanco [ 04/Aug/10 ]

Already merged into core.

Comment by Benjamin Eberlei [ 04/Aug/10 ]

But it is not enabled yet Plus we need tests to verify this works in high concurrency enviroments and does not pass the same id twice.

Furthermore the DAtabase Platform Methods are completly missing. No implementations yet.

Comment by Benjamin Eberlei [ 04/Aug/10 ]

Schema-Tool support is also missing.





[DDC-567] Foreign Key to Unique Field Update Failure Created: 03/May/10  Updated: 08/Oct/12

Status: Reopened
Project: Doctrine 2 - ORM
Component/s: ORM
Affects Version/s: 2.0-BETA2
Fix Version/s: None
Security Level: All

Type: New Feature Priority: Trivial
Reporter: Michael Ridgway Assignee: Roman S. Borschel
Resolution: Unresolved Votes: 2
Labels: None

Attachments: File DDC567Test.php    

 Description   

I am getting an error: 'Notice: Undefined index: sysname in ./libraries/Doctrine/ORM/Persisters/BasicEntityPersister.php on line 434' when I try to flush a change to a property that references a unique field on another object.

From poking around in the _prepareUpdateData function, it seems that it only allows you to use identifier fields:

$newValId = $uow->getEntityIdentifier($newVal);

..

$result[$owningTable][$sourceColumn] = $newValId[$targetClass->fieldNames[$targetColumn]];

I'll see if I can get a test case for this set up.



 Comments   
Comment by Roman S. Borschel [ 03/May/10 ]

Hi. That is right. Foreign keys (join columns) must point to primary keys, not arbitrary other columns, whether they're unique or not, Doctrine does not know.

In other words, joinColumn must always refer to an identifier/pk. I'm not sure but I think anything else would be a pretty strange relational model, too, but there may be usecases we have not yet encountered.

I'm afraid this will not be possible and would be very hard to implement. Of course if somebody has a patch we happily accept it (after reviewing).

Leaving this open in the case somebody wants to work on it.

Comment by Michael Ridgway [ 03/May/10 ]

A minimal test case. Removing the first flush produces the same error, so this seems to be a bug on inserts as well.

Comment by Roman S. Borschel [ 03/May/10 ]

Its not really a bug but rather a new feature This was not intended to work so far.

Comment by Michael Ridgway [ 03/May/10 ]

Ah, ok. Maybe it didn't work before. I don't know where I got the idea that it did.

Thanks.

Comment by Michael Ridgway [ 03/May/10 ]

Oops, closed it before I noticed you said you wanted to leave it open.

Comment by Roman S. Borschel [ 03/May/10 ]

Thanks for the testcase though, it is useful. In your concrete example, is it not an option to make the sysname the @Id ?

Comment by Michael Ridgway [ 03/May/10 ]

Yes. That is definitely the way it should be done in this case. I can't really think of a case to have a reference to a unique key while still having an Id on it, except when you're working with an existing, poorly designed database (which is our case).

The reason I assumed this was possible is that the references actually work for lazy loading, but as soon as you start changing the references it throws this error.

Comment by Roman S. Borschel [ 14/May/10 ]

Lowering priority.

Comment by Thomas Subera [ 08/Oct/12 ]

although we would also need this i would suggest adding an error message if the associated column is not found in $newValId. (class BasicEntityPersister.php _prepareUpdateData)

otherwise the field is populated with null leaving the developer debugging an hour :-/

thx





Generated at Sat May 25 10:16:49 UTC 2013 using JIRA 5.2.7#850-sha1:b2af0c8dc8537b36121c6a579fabbdf79fc919e5.